at.happyproto.server.addDomain

happyproto.at

Documentation

Add a custom domain to one of the caller's instances. It starts pending, with the DNS records to publish. Customers only.

main procedure

Add a custom domain to one of the caller's instances. It starts pending, with the DNS records to publish. Customers only.

Input

Encodingapplication/json
hostname string Required

The hostname, such as app.example.com. No scheme, port or path.

idempotencyKey string Required

A UUID the client generates once per intended change and resends on every retry of it, so a retry gets the original reply instead of acting twice.

instanceId string Required

The instance's UUID.

Output

Encodingapplication/json
domain ref#domain Required

No description available.

Errors

AuthRequired This endpoint requires an authenticated caller.
Forbidden The caller is not a HappyProto customer, or the provisioner refused them.
InvalidRequest instanceId or idempotencyKey is not a UUID, or hostname is missing or too long.
NotFound No such instance or domain, or it is not the caller's. The cases are indistinguishable.
NotAvailable Custom domains are not switched on yet.
InvalidSlug Passed through from the provisioner.
SlugTaken Passed through from the provisioner.
NotEntitled Passed through from the provisioner.
InstanceLimit Passed through from the provisioner.
NoCapacity Passed through from the provisioner.
OperationInProgress Passed through from the provisioner: the instance is already changing, or a request with this idempotencyKey is still running.
InvalidHostname The hostname is not a valid public hostname: no scheme, port, path, wildcard or IP address.
PlatformHostname The hostname is HappyProto's own, or under one of its domains.
DomainExists The instance already has this hostname.
DomainLimit The instance already has as many custom domains as it may.
TooSoon Passed through from the provisioner.
DomainIsPrimary Passed through from the provisioner.
NotVerified Passed through from the provisioner.
CertificateNotReady Passed through from the provisioner.
VersionTooOld Passed through from the provisioner.
Upstream The provisioner is unreachable, not configured, or answered with an error it does not explain to callers, or the job could not be started.
Try It

Requests are sent directly from your browser. Some servers may block requests due to CORS.

Base URL for XRPC calls (e.g., https://bsky.social)
Enter valid JSON for the request body
View raw schema
{
  "description": "Add a custom domain to one of the caller's instances. It starts pending, with the DNS records to publish. Customers only.",
  "errors": [
    {
      "description": "This endpoint requires an authenticated caller.",
      "name": "AuthRequired"
    },
    {
      "description": "The caller is not a HappyProto customer, or the provisioner refused them.",
      "name": "Forbidden"
    },
    {
      "description": "instanceId or idempotencyKey is not a UUID, or hostname is missing or too long.",
      "name": "InvalidRequest"
    },
    {
      "description": "No such instance or domain, or it is not the caller's. The cases are indistinguishable.",
      "name": "NotFound"
    },
    {
      "description": "Custom domains are not switched on yet.",
      "name": "NotAvailable"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "InvalidSlug"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "SlugTaken"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "NotEntitled"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "InstanceLimit"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "NoCapacity"
    },
    {
      "description": "Passed through from the provisioner: the instance is already changing, or a request with this idempotencyKey is still running.",
      "name": "OperationInProgress"
    },
    {
      "description": "The hostname is not a valid public hostname: no scheme, port, path, wildcard or IP address.",
      "name": "InvalidHostname"
    },
    {
      "description": "The hostname is HappyProto's own, or under one of its domains.",
      "name": "PlatformHostname"
    },
    {
      "description": "The instance already has this hostname.",
      "name": "DomainExists"
    },
    {
      "description": "The instance already has as many custom domains as it may.",
      "name": "DomainLimit"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "TooSoon"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "DomainIsPrimary"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "NotVerified"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "CertificateNotReady"
    },
    {
      "description": "Passed through from the provisioner.",
      "name": "VersionTooOld"
    },
    {
      "description": "The provisioner is unreachable, not configured, or answered with an error it does not explain to callers, or the job could not be started.",
      "name": "Upstream"
    }
  ],
  "input": {
    "encoding": "application/json",
    "schema": {
      "properties": {
        "hostname": {
          "description": "The hostname, such as app.example.com. No scheme, port or path.",
          "type": "string"
        },
        "idempotencyKey": {
          "description": "A UUID the client generates once per intended change and resends on every retry of it, so a retry gets the original reply instead of acting twice.",
          "type": "string"
        },
        "instanceId": {
          "description": "The instance's UUID.",
          "type": "string"
        }
      },
      "required": [
        "instanceId",
        "hostname",
        "idempotencyKey"
      ],
      "type": "object"
    }
  },
  "output": {
    "encoding": "application/json",
    "schema": {
      "properties": {
        "domain": {
          "ref": "#domain",
          "type": "ref"
        }
      },
      "required": [
        "domain"
      ],
      "type": "object"
    }
  },
  "type": "procedure"
}
altRecord object

No description available.

Properties

type string Required

A.

value string Required

The instance host's public IPv4.

View raw schema
{
  "properties": {
    "type": {
      "description": "A.",
      "type": "string"
    },
    "value": {
      "description": "The instance host's public IPv4.",
      "type": "string"
    }
  },
  "required": [
    "type",
    "value"
  ],
  "type": "object"
}
checks object

No description available.

Properties

checkedAt string Required

When the check ran.

ownership string Required

Whether the TXT record carries this claim's token.

Known values: ok, missing, error
pointing string Optional

Whether the hostname resolves to the instance's host. Absent when the check didn't get that far, such as when the TXT record was missing.

Known values: ok, elsewhere, error
View raw schema
{
  "properties": {
    "checkedAt": {
      "description": "When the check ran.",
      "type": "string"
    },
    "ownership": {
      "description": "Whether the TXT record carries this claim's token.",
      "knownValues": [
        "ok",
        "missing",
        "error"
      ],
      "type": "string"
    },
    "pointing": {
      "description": "Whether the hostname resolves to the instance's host. Absent when the check didn't get that far, such as when the TXT record was missing.",
      "knownValues": [
        "ok",
        "elsewhere",
        "error"
      ],
      "type": "string"
    }
  },
  "required": [
    "ownership",
    "checkedAt"
  ],
  "type": "object"
}
domain object

A custom domain on one of the caller's instances.

Properties

checks ref #checks Optional

The latest DNS check. Absent until the first check has run.

createdAt string Required

When the domain was added.

expiresAt string Optional

When a pending claim expires if it is never verified. Absent once verified.

hostname string Required

The hostname, lowercase, internationalized names in punycode.

id string Required

The domain's UUID.

lapsesAt string Optional

When HappyProto stops serving the domain if its TXT record stays missing. Absent while the record is present.

primary boolean Required

Whether this is the instance's primary domain, the one its PUBLIC_URL follows.

records array of ref#record Required

The DNS records the customer publishes: the TXT that proves ownership, then the CNAME that points the hostname at the instance.

serving string Required

Whether the domain actually works: off until it is verified, issuing while its certificate is ordered, live once it serves over HTTPS.

Known values: routing, issuing, live, failed, off
state string Required

pending: waiting for the DNS records. verified: proven and served. lapsed: the TXT record went missing, and HappyProto stopped serving it; it recovers if the record comes back before expiresAt.

Known values: pending, verified, lapsed
verifiedAt string Optional

When the domain was first verified.

View raw schema
{
  "description": "A custom domain on one of the caller's instances.",
  "properties": {
    "checks": {
      "description": "The latest DNS check. Absent until the first check has run.",
      "ref": "#checks",
      "type": "ref"
    },
    "createdAt": {
      "description": "When the domain was added.",
      "type": "string"
    },
    "expiresAt": {
      "description": "When a pending claim expires if it is never verified. Absent once verified.",
      "type": "string"
    },
    "hostname": {
      "description": "The hostname, lowercase, internationalized names in punycode.",
      "type": "string"
    },
    "id": {
      "description": "The domain's UUID.",
      "type": "string"
    },
    "lapsesAt": {
      "description": "When HappyProto stops serving the domain if its TXT record stays missing. Absent while the record is present.",
      "type": "string"
    },
    "primary": {
      "description": "Whether this is the instance's primary domain, the one its PUBLIC_URL follows.",
      "type": "boolean"
    },
    "records": {
      "description": "The DNS records the customer publishes: the TXT that proves ownership, then the CNAME that points the hostname at the instance.",
      "items": {
        "ref": "#record",
        "type": "ref"
      },
      "type": "array"
    },
    "serving": {
      "description": "Whether the domain actually works: off until it is verified, issuing while its certificate is ordered, live once it serves over HTTPS.",
      "knownValues": [
        "routing",
        "issuing",
        "live",
        "failed",
        "off"
      ],
      "type": "string"
    },
    "state": {
      "description": "pending: waiting for the DNS records. verified: proven and served. lapsed: the TXT record went missing, and HappyProto stopped serving it; it recovers if the record comes back before expiresAt.",
      "knownValues": [
        "pending",
        "verified",
        "lapsed"
      ],
      "type": "string"
    },
    "verifiedAt": {
      "description": "When the domain was first verified.",
      "type": "string"
    }
  },
  "required": [
    "id",
    "hostname",
    "state",
    "primary",
    "records",
    "serving",
    "createdAt"
  ],
  "type": "object"
}
record object

No description available.

Properties

alt ref #altRecord Optional

For an apex name, which cannot hold a CNAME: the A record to publish instead. Absent when the instance's host has no public IPv4.

name string Required

The record's name.

type string Required

TXT or CNAME.

value string Required

The record's value.

View raw schema
{
  "properties": {
    "alt": {
      "description": "For an apex name, which cannot hold a CNAME: the A record to publish instead. Absent when the instance's host has no public IPv4.",
      "ref": "#altRecord",
      "type": "ref"
    },
    "name": {
      "description": "The record's name.",
      "type": "string"
    },
    "type": {
      "description": "TXT or CNAME.",
      "type": "string"
    },
    "value": {
      "description": "The record's value.",
      "type": "string"
    }
  },
  "required": [
    "type",
    "name",
    "value"
  ],
  "type": "object"
}

Lexicon Garden

@