Skip to content

Domain

A Domain is a hostname that points at a Thing, with a role, a status, and a lifecycle tracked as data.

Properties

PropertyTypeRequiredDescription
hostnamestringrequiredThe name, such as example.com.
rolestringrequiredWhat the Domain does for the Thing it serves; a defensive name takes redirect.
acquiredstringOne of claimed, purchased, or connected.
statestringrequiredWhere the Domain stands; verifying, live, degraded, expiring and lapsed are observed, the rest follow an Action.
registrantPartyThe owner of record: the holding Company while held, or the holder of a self-serve Startup’s Stripe account.
expiresAtdatetimeWhen the registration ends, as the registrar reports it; empty for a claimed Domain.
autoRenewbooleanTrue when renewal runs without a Decision; false sends the Domain through renewal review.
renewalPricemoneyWhat the next renewal costs, which for a premium name differs from the purchase price. Never randomized.
transferableAtdatetimeThe first moment the registrar allows a transfer out, after any registration, transfer or registrant lock.
namesstringHow its subdomains are given out: explicit records only, or one-label claims by other Startups.
publicSuffixbooleanTrue once the public suffix list browsers ship carries the Domain; an issuing Domain gives out no label before then.
registrarAccountstringThe registrar account that holds the Domain: one per Startup, never shared with a sibling.
registryLockbooleanTrue when the registry refuses transfer, update and delete until a verified out-of-band request lifts it.
certificatejsonCertificate state (pending, active, renewing or failed), its expiry, and the failing check with its fix.
validationstringdelegated proves control through a CNAME to the platform; serving is for an apex that cannot hold one.
walletsEnabledbooleanTrue once Stripe lists the Domain as a payment method domain on the Startup’s account.
carriedIdentitybooleanTrue once the Domain received mail, hosted a Mailbox or verified an outside account; it never resets.
toDomainFor a redirect: the canonical Domain it forwards to permanently, path and query kept.

Object

JSON
{
  "$id": "https://api.sb/kilnbakery.com/domains/domain_1",
  "$type": "Domain",
  "hostname": "kilnbakery.com",
  "role": "canonical",
  "acquired": "claimed",
  "state": "verifying",
  "registrant": "party_1",
  "expiresAt": "2026-10-22T12:00:00Z",
  "autoRenew": true,
  "renewalPrice": {
    "amount": 9,
    "currency": "USD"
  },
  "transferableAt": "2026-10-22T12:00:00Z",
  "names": "closed",
  "publicSuffix": true,
  "registrarAccount": "registrar_account_1",
  "registryLock": true,
  "certificate": {},
  "validation": "delegated",
  "walletsEnabled": true,
  "carriedIdentity": true,
  "to": "domain_1"
}

Relationships

  • A Domain hosts one Site: a Site answers on one or more Domains; each Domain serves one Site. hosts, inverse hostedAt.
  • A Domain mounts many Interfaces: an Interface answers requests on the hostnames it is mounted on. mounts, inverse mountedOn.
  • A Domain records many DNS Records: a Domain answers DNS from its records; each record belongs to one Domain. records, inverse answersFor.
  • A Domain is registered to one Startup: a Startup holds each Domain registration and pays for the hostname. registeredTo, inverse domains.
  • A Domain serves one Tenant: a Tenant answers on the names its Customer connects; each such Domain serves one Tenant. serves, inverse hostnames.
  • A Domain is verified by one Tenant: a Tenant proves control of its Customer’s email domain, so sign-ins on that domain follow the Tenant’s policy. verifiedBy, inverse verifies.

Lifecycle

Domain lifecycle: candidate, held, claimed, registered, connected, verifying, live, degraded, expiring, lapsed, renewed, transferred (ends), released (ends)candidate → held: Domain.registercandidate → registered: Domain.registercandidate → claimed: Domain.claimcandidate → connected: Domain.connectheld → claimed: Domain.claimheld → released: Domain.releaseclaimed → live: Domain.verifyclaimed → released: Domain.releaseregistered → verifying: Domain.verifyconnected → verifying: Domain.verifyverifying → live: Domain.verifyverifying → degraded: Domain.verifylive → degraded: Domain.verifylive → expiring: on Domain.renewalDuelive → renewed: Domain.renewlive → transferred: Domain.transferlive → released: Domain.releasedegraded → live: Domain.verifydegraded → released: Domain.releaseexpiring → renewed: Domain.renewexpiring → lapsed: on Domain.expiredlapsed → renewed: Domain.renewlapsed → released: Domain.releaserenewed → live: Domain.verifycandidateheldclaimedregisteredconnectedverifyinglivedegradedexpiringrenewedlapsedtransferredreleased
StateMeaningMoves to
candidate (first)A name found by search that no one here holds yet.held by Domain.register; registered by Domain.register; claimed by Domain.claim; connected by Domain.connect
heldRegistered to the holding Company and not yet assigned to a Startup.claimed by Domain.claim; released by Domain.release
claimedAssigned to a Startup: a label under an issuing Domain, or a held Domain.live by Domain.verify; released by Domain.release
registeredRegistered to its owner of record and pointed at the Startup’s address.verifying by Domain.verify
connectedAttached from another registrar while its ownership proof is checked.verifying by Domain.verify
verifyingIts first DNS, ownership and certificate checks are running.live by Domain.verify; degraded by Domain.verify
liveServing, with its DNS, ownership and certificate checks passing.degraded by Domain.verify; expiring on Domain.renewalDue; renewed by Domain.renew; transferred by Domain.transfer; released by Domain.release
degradedA check failed; a degraded canonical Domain opens an Incident.live by Domain.verify; released by Domain.release
expiringInside its renewal window with no renewal yet.renewed by Domain.renew; lapsed on Domain.expired
lapsedIts registration ended unrenewed, and the registrar may still restore it.renewed by Domain.renew; released by Domain.release
renewedExtended by whole years at its renewal price.live by Domain.verify
transferredMoved to another holder or registrar, with its record and history kept.None: it ends here.
releasedIts registration or claim ended, and its record, history and aliases are kept.None: it ends here.

Verbs

  1. createCreates a Domain.
    POST /{namespace}/domainsdoDomain.created
  2. getReturns one Domain by id.
    GET /{namespace}/domains/{id}readNo Event
  3. listReturns Domains, newest first, one page at a time.
    GET /{namespace}/domainsreadNo Event
  4. updateChanges the given properties of a Domain.
    PATCH /{namespace}/domains/{id}doDomain.updated
  5. deleteDeletes a Domain; its history is kept.
    DELETE /{namespace}/domains/{id}doDomain.deleted
  6. authenticateAuthenticate writes a Domain’s SPF, DKIM and DMARC records and verifies them before its first send.
    POST /{namespace}/domains/{domain}/authenticatedoDomain.authenticated
  7. benchmarkBenchmark measures a Domain’s estimated traffic, ranking Keywords, authority and referring domains beside the competitors named.
    POST /{namespace}/domains/benchmarkdoDomain.benchmarked
  8. claimClaim gives a Startup a one-label name under an issuing Domain, or assigns it a held Domain through an approved Change.
    POST /{namespace}/domains/claimdoDomain.claimed
  9. connectConnect attaches a hostname a Startup already holds and verifies ownership through DNS.
    POST /{namespace}/domains/connectdoDomain.connected
  10. registerRegister buys a hostname for a Startup and points it at the Startup’s address.
    POST /{namespace}/domains/registerdoDomain.registered
  11. releaseRelease lets a Domain’s registration or claim end, keeping its record, history and aliases.
    POST /{namespace}/domains/{domain}/releasedoDomain.released
  12. renewRenew extends a Domain’s registration by whole years at its renewal price, paid by its owner of record.
    POST /{namespace}/domains/{domain}/renewdoDomain.renewed
  13. searchSearch lists candidate names with availability, first-year price, renewal price and the rules of each extension.
    POST /{namespace}/domains/searchdoDomain.searched
  14. transferTransfer moves a Domain’s registration to another holder or registrar, with its records intact.
    POST /{namespace}/domains/{domain}/transferdoDomain.transferred
  15. verifyVerify checks a Domain’s DNS, ownership and certificate again and records each result, with the fix for any failure.
    POST /{namespace}/domains/{domain}/verifydoDomain.verified

Events

Events no Verb emits. Each Verb’s Event is in the Verbs table above; every Event is delivered in the same shape.

Domain.expired

A Domain’s registration passed expiresAt unrenewed; the registrar may still restore it. Raised by a clock.

FieldTypeRequiredDescription
namestringrequiredDomain.expired.
atdatetimerequiredWhen it happened.
seqintegerIts position in the namespace, one more than the Event before; any seq is a cursor into the history.
datajsonrequiredThe Thing as the Action left it.
data.domainDomainrequiredThe Domain as the change left it.
data.domain.hostnamestringrequiredThe name, such as example.com.
data.domain.rolestringrequiredWhat the Domain does for the Thing it serves; a defensive name takes redirect.
data.domain.acquiredstringOne of claimed, purchased, or connected.
data.domain.statestringrequiredWhere the Domain stands; verifying, live, degraded, expiring and lapsed are observed, the rest follow an Action.
data.domain.registrantPartyThe owner of record: the holding Company while held, or the holder of a self-serve Startup’s Stripe account.
data.domain.expiresAtdatetimeWhen the registration ends, as the registrar reports it; empty for a claimed Domain.
data.domain.autoRenewbooleanTrue when renewal runs without a Decision; false sends the Domain through renewal review.
data.domain.renewalPricemoneyWhat the next renewal costs, which for a premium name differs from the purchase price.
data.domain.transferableAtdatetimeThe first moment the registrar allows a transfer out, after any registration, transfer or registrant lock.
data.domain.namesstringHow its subdomains are given out: explicit records only, or one-label claims by other Startups.
data.domain.publicSuffixbooleanTrue once the public suffix list browsers ship carries the Domain; an issuing Domain gives out no label before then.
data.domain.registrarAccountstringThe registrar account that holds the Domain: one per Startup, never shared with a sibling.
data.domain.registryLockbooleanTrue when the registry refuses transfer, update and delete until a verified out-of-band request lifts it.
data.domain.certificatejsonCertificate state (pending, active, renewing or failed), its expiry, and the failing check with its fix.
data.domain.validationstringdelegated proves control through a CNAME to the platform; serving is for an apex that cannot hold one.
data.domain.walletsEnabledbooleanTrue once Stripe lists the Domain as a payment method domain on the Startup’s account.
data.domain.carriedIdentitybooleanTrue once the Domain received mail, hosted a Mailbox or verified an outside account; it never resets.
data.domain.toDomainFor a redirect: the canonical Domain it forwards to permanently, path and query kept.
data.previous.statestringrequiredThe state before this Event: expiring.
JSON
{
  "$id": "https://api.sb/kilnbakery.com/events/event_1",
  "$type": "Event",
  "name": "Domain.expired",
  "at": "2026-10-22T12:00:00Z",
  "data": {
    "domain": {
      "$id": "https://api.sb/kilnbakery.com/domains/domain_1",
      "$type": "Domain",
      "hostname": "kilnbakery.com",
      "role": "canonical",
      "acquired": "claimed",
      "state": "lapsed",
      "registrant": "party_1",
      "expiresAt": "2026-10-22T12:00:00Z",
      "autoRenew": true,
      "renewalPrice": {
        "amount": 9,
        "currency": "USD"
      },
      "transferableAt": "2026-10-22T12:00:00Z",
      "names": "closed",
      "publicSuffix": true,
      "registrarAccount": "registrar_account_1",
      "registryLock": true,
      "certificate": {},
      "validation": "delegated",
      "walletsEnabled": true,
      "carriedIdentity": true,
      "to": "domain_1"
    },
    "previous": {
      "state": "expiring"
    }
  },
  "seq": 1
}

Domain.renewalDue

A live Domain entered its renewal window with no renewal yet. Raised by a clock.

FieldTypeRequiredDescription
namestringrequiredDomain.renewalDue.
atdatetimerequiredWhen it happened.
seqintegerIts position in the namespace, one more than the Event before; any seq is a cursor into the history.
datajsonrequiredThe Thing as the Action left it.
data.domainDomainrequiredThe Domain as the change left it.
data.domain.hostnamestringrequiredThe name, such as example.com.
data.domain.rolestringrequiredWhat the Domain does for the Thing it serves; a defensive name takes redirect.
data.domain.acquiredstringOne of claimed, purchased, or connected.
data.domain.statestringrequiredWhere the Domain stands; verifying, live, degraded, expiring and lapsed are observed, the rest follow an Action.
data.domain.registrantPartyThe owner of record: the holding Company while held, or the holder of a self-serve Startup’s Stripe account.
data.domain.expiresAtdatetimeWhen the registration ends, as the registrar reports it; empty for a claimed Domain.
data.domain.autoRenewbooleanTrue when renewal runs without a Decision; false sends the Domain through renewal review.
data.domain.renewalPricemoneyWhat the next renewal costs, which for a premium name differs from the purchase price.
data.domain.transferableAtdatetimeThe first moment the registrar allows a transfer out, after any registration, transfer or registrant lock.
data.domain.namesstringHow its subdomains are given out: explicit records only, or one-label claims by other Startups.
data.domain.publicSuffixbooleanTrue once the public suffix list browsers ship carries the Domain; an issuing Domain gives out no label before then.
data.domain.registrarAccountstringThe registrar account that holds the Domain: one per Startup, never shared with a sibling.
data.domain.registryLockbooleanTrue when the registry refuses transfer, update and delete until a verified out-of-band request lifts it.
data.domain.certificatejsonCertificate state (pending, active, renewing or failed), its expiry, and the failing check with its fix.
data.domain.validationstringdelegated proves control through a CNAME to the platform; serving is for an apex that cannot hold one.
data.domain.walletsEnabledbooleanTrue once Stripe lists the Domain as a payment method domain on the Startup’s account.
data.domain.carriedIdentitybooleanTrue once the Domain received mail, hosted a Mailbox or verified an outside account; it never resets.
data.domain.toDomainFor a redirect: the canonical Domain it forwards to permanently, path and query kept.
data.daysLeftintegerrequiredDays until expiresAt.
data.previous.statestringrequiredThe state before this Event: live.
JSON
{
  "$id": "https://api.sb/kilnbakery.com/events/event_1",
  "$type": "Event",
  "name": "Domain.renewalDue",
  "at": "2026-10-22T12:00:00Z",
  "data": {
    "domain": {
      "$id": "https://api.sb/kilnbakery.com/domains/domain_1",
      "$type": "Domain",
      "hostname": "kilnbakery.com",
      "role": "canonical",
      "acquired": "claimed",
      "state": "expiring",
      "registrant": "party_1",
      "expiresAt": "2026-10-22T12:00:00Z",
      "autoRenew": true,
      "renewalPrice": {
        "amount": 9,
        "currency": "USD"
      },
      "transferableAt": "2026-10-22T12:00:00Z",
      "names": "closed",
      "publicSuffix": true,
      "registrarAccount": "registrar_account_1",
      "registryLock": true,
      "certificate": {},
      "validation": "delegated",
      "walletsEnabled": true,
      "carriedIdentity": true,
      "to": "domain_1"
    },
    "daysLeft": 30,
    "previous": {
      "state": "live"
    }
  },
  "seq": 1
}

Permissions

Which Access level may call each Verb. One-way Verbs wait their delay window.

Operationowneradminmemberviewer
Domain.createYesYesYesNo
Domain.getYesYesYesYes
Domain.listYesYesYesYes
Domain.updateYesYesYesNo
Domain.deleteYesYesYesNo
Domain.authenticateYesYesYesNo
Domain.benchmarkYesYesYesNo
Domain.claimYesYesYesNo
Domain.connectYesYesYesNo
Domain.registerYesNoNoNo
Domain.releaseYesNoNoNo
Domain.renewYesNoNoNo
Domain.searchYesYesYesNo
Domain.transferYesNoNoNo
Domain.verifyYesYesYesNo

Call it

Text
Register the domain “patentpad.com” with a startup.

Example

Text
hostname            role        state   to
permitly.dev        canonical   live            the Site, /docs, /portal, /api and /mcp
api.permitly.dev    alias       live            the same API as /api
permitly.com        redirect    live    permitly.dev