Custom Domains

Serve Blue on your own hostname — create, verify via DNS, and list custom domains for your organization.


White-label customers can serve Blue’s application, public forms, and file links from their own hostname instead of blue.cc. A custom domain is a CustomDomain object: a hostname bound to one application type for one organization, with a DNS verification status Blue refreshes on demand. Organizations are Company objects in the API.

This page covers the full lifecycle — create a domain, point it at Blue with a CNAME, verify it, update or delete it, and list the domains for an organization. For routing outbound mail through your own server, see SMTP Credentials; to rebrand Blue’s transactional emails, see Email Templates.

White-label is required for writes, not reads

Every mutation on this page requires the organization to have the white_label feature enabled (bundled with the Pro plan) — plain membership is not enough. The customDomains query requires only that you are a member of the organization, no feature gate. That asymmetry is intentional and applies across the whole Custom Domains & Email section.

The CustomDomain type

FieldTypeDescription
idID!Unique identifier.
uidString!Short public identifier.
nameString!The hostname, e.g. app.example.com.
applicationTypeApplicationTypeWhich Blue surface this hostname serves. See ApplicationType.
verificationStatusString"verified", "failed", or null if never verified. Set by verifyCustomDomain.
companyCompany!The organization that owns the domain.
userUser!The user who created the domain.
createdAtDateTime!Creation timestamp.
updatedAtDateTime!Last-update timestamp.

ApplicationType

ValueServesAccepted by createCustomDomain
APPLICATIONThe main Blue web app.Yes
FORMSPublic forms.Yes
FILESFile links and downloads.Yes
DOCUMENTATIONDocumentation sites.No — rejected

An organization may register one domain per application type — e.g. one APPLICATION domain and one FORMS domain, but not two APPLICATION domains. createCustomDomain and verifyCustomDomain reject DOCUMENTATION with APPLICATION_TYPE_NOT_FOUND.

Create a domain

Use the createCustomDomain mutation to register a hostname for an organization. Blue provisions the domain on its hosting layer and returns the new CustomDomain with verificationStatus: null — it is not live until DNS is in place and you verify it.

Request

mutation CreateCustomDomain {
  createCustomDomain(
    input: { name: "app.example.com", companyId: "company_123", applicationType: APPLICATION }
  ) {
    id
    uid
    name
    applicationType
    verificationStatus
  }
}

Parameters

CreateCustomDomainInput

ParameterTypeRequiredDescription
nameString!YesThe hostname to register, e.g. app.example.com.
companyIdString!YesThe organization that will own the domain. Accepts an ID or slug. Must have the white_label feature.
applicationTypeApplicationTypeYes¹One of APPLICATION, FORMS, or FILES. DOCUMENTATION is rejected. See ApplicationType.

¹ The field is nullable in the schema, but the resolver rejects a missing or DOCUMENTATION value with APPLICATION_TYPE_NOT_FOUND. Always pass one of the three accepted values.

Response

{
  "data": {
    "createCustomDomain": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "uid": "cd_8f3a2c1e",
      "name": "app.example.com",
      "applicationType": "APPLICATION",
      "verificationStatus": null
    }
  }
}

Errors

CodeWhen
APPLICATION_TYPE_NOT_FOUNDapplicationType is omitted or is DOCUMENTATION.
CUSTOM_DOMAIN_IN_USEThe hostname is already registered (by any organization). Hostnames are globally unique.
CUSTOM_DOMAIN_ALREADY_EXISTSThis organization already has a domain for that application type.
CUSTOM_DOMAIN_CREATE_ERRORBlue’s hosting layer rejected the domain — usually DNS isn’t pointing at Blue yet. Add the CNAME, wait, and retry.
COMPANY_NOT_FOUNDcompanyId does not resolve to an organization you belong to, or it lacks the white_label feature.

Verify a domain

Use the verifyCustomDomain mutation to check that a hostname’s DNS points at Blue. It runs a live CNAME lookup against the expected target for the domain’s application type (with an IPv4 fallback to Blue’s server address), writes the result to verificationStatus, and returns true when the domain is verified.

This mutation takes the hostname (name), not the domain ID.

Request

mutation VerifyCustomDomain {
  verifyCustomDomain(name: "app.example.com")
}

Response

{
  "data": {
    "verifyCustomDomain": true
  }
}

A true result sets verificationStatus to "verified"; false sets it to "failed". Re-read the domain with customDomains to see the persisted status.

Verification is throttled and live

Each hostname can be verified at most once per 10 seconds. A call within that window returns the last known status without re-running the DNS lookup. The check is a real DNS resolution: if it succeeds and the CNAME (or fallback IP) matches, the domain is verified; if the domain resolves but doesn’t match, it is failed. On a transient network error the mutation throws and leaves verificationStatus unchanged — retry rather than treating it as a failure.

Errors

CodeWhen
CUSTOM_DOMAIN_NOT_FOUNDNo domain is registered with that hostname.
APPLICATION_TYPE_NOT_FOUNDThe domain has no application type, or is a DOCUMENTATION domain.
COMPANY_NOT_FOUNDYou don’t belong to the owning organization, or it lacks the white_label feature.

Update a domain

Use the updateCustomDomain mutation to change a domain’s hostname. Blue removes the old hostname from its hosting layer, provisions the new one, migrates the white-label assets, and resets verificationStatus to null — re-run verifyCustomDomain after the DNS for the new hostname is in place. The application type cannot be changed; delete and recreate to move to a different type.

Request

mutation UpdateCustomDomain {
  updateCustomDomain(input: { id: "domain_123", name: "app.newdomain.com" }) {
    id
    name
    applicationType
    verificationStatus
  }
}

Parameters

UpdateCustomDomainInput

ParameterTypeRequiredDescription
idString!YesThe CustomDomain ID to update.
nameString!YesThe new hostname.

Response

{
  "data": {
    "updateCustomDomain": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "name": "app.newdomain.com",
      "applicationType": "APPLICATION",
      "verificationStatus": null
    }
  }
}

Errors

CodeWhen
CUSTOM_DOMAIN_NOT_FOUNDNo domain matches id.
CUSTOM_DOMAIN_IN_USEThe new hostname is already registered.
CUSTOM_DOMAIN_CREATE_ERRORBlue’s hosting layer rejected the new hostname — usually a DNS issue. Retry.
COMPANY_NOT_FOUNDYou don’t belong to the owning organization, or it lacks the white_label feature.

Delete a domain

Use the deleteCustomDomain mutation to remove a domain. Blue tears it down on the hosting layer, clears the organization’s white-label logo/favicon/manifest assets, and deletes the record. Returns true on success. This is a bare-scalar mutation — it takes no sub-selection.

Request

mutation DeleteCustomDomain {
  deleteCustomDomain(id: "domain_123")
}

Response

{
  "data": {
    "deleteCustomDomain": true
  }
}

Errors

CodeWhen
CUSTOM_DOMAIN_NOT_FOUNDNo domain matches id.
COMPANY_NOT_FOUNDYou don’t belong to the owning organization, or it lacks the white_label feature.

List domains

Use the customDomains query to page through an organization’s domains. It returns a CustomDomainPagination object — items plus a pageInfo. Unlike the mutations, this query requires only organization membership, not the white_label feature.

Pass filter.companyId to target a specific organization — useful when your token belongs to multiple organizations. Omit it and the query falls back to the organization in your X-Bloo-Company-ID header.

Request

query CustomDomains {
  customDomains(filter: { companyId: "company_123" }, skip: 0, take: 20) {
    items {
      id
      name
      applicationType
      verificationStatus
      createdAt
    }
    pageInfo {
      totalItems
      totalPages
      page
      perPage
      hasNextPage
      hasPreviousPage
    }
  }
}

Parameters

ParameterTypeRequiredDescription
filterCustomDomainFilterInput!YesFilter object. See below. The argument is required, but its only field is optional.
skipIntNoNumber of items to skip. Defaults to 0.
takeIntNoPage size. Defaults to 20.

CustomDomainFilterInput

FieldTypeRequiredDescription
companyIdStringNoOrganization to list domains for. Accepts an ID or slug. If omitted, falls back to the organization in X-Bloo-Company-ID.

Response

{
  "data": {
    "customDomains": {
      "items": [
        {
          "id": "clm4n8qwx000008l0g4oxdqn7",
          "name": "app.example.com",
          "applicationType": "APPLICATION",
          "verificationStatus": "verified",
          "createdAt": "2026-05-20T14:32:09.000Z"
        }
      ],
      "pageInfo": {
        "totalItems": 1,
        "totalPages": 1,
        "page": 1,
        "perPage": 20,
        "hasNextPage": false,
        "hasPreviousPage": false
      }
    }
  }
}

CustomDomainPagination

FieldTypeDescription
items[CustomDomain!]!The domains on this page.
pageInfoPageInfo!Pagination metadata. See PageInfo.

PageInfo

FieldTypeDescription
totalItemsIntTotal domains matching the filter.
totalPagesIntTotal number of pages.
pageIntCurrent page (1-based).
perPageIntItems per page (the take value).
hasNextPageBoolean!Whether a next page exists.
hasPreviousPageBoolean!Whether a previous page exists.

Errors

CodeWhen
COMPANY_NOT_FOUNDNo filter.companyId and no X-Bloo-Company-ID header to fall back to.
FORBIDDENYou are not a member of the target organization.

Setting up a custom domain end to end

  1. Create the domain with createCustomDomain, choosing the right applicationType. It comes back with verificationStatus: null.
  2. Point DNS at Blue: add the CNAME record for your hostname as instructed in your Blue workspace settings. Newly added DNS records can take a few minutes to propagate.
  3. Verify with verifyCustomDomain. When it returns true, the domain is live and verificationStatus is "verified".

If createCustomDomain returns CUSTOM_DOMAIN_CREATE_ERROR, the DNS almost certainly isn’t pointing at Blue yet — add the CNAME first, wait for propagation, then retry.

Permissions

  • Mutations (createCustomDomain, updateCustomDomain, deleteCustomDomain, verifyCustomDomain): you must be a member of the owning organization and that organization must have the white_label feature enabled.
  • customDomains query: organization membership only — no feature gate. With filter.companyId you can list domains for any organization you belong to.