Domains API
Purpose and Scope
The Domains API is the public surface for managing the hostnames that Dub can use when creating and serving short links. A domain is the branded part of a short link, such as a workspace-owned custom domain, a Dub-provided default branded domain, or a domain that may be purchased through supported registration flows. This page is a reference-oriented guide for the domain routes exposed through Dub’s OpenAPI assembly and the CLI helper that reads domain choices for local command workflows.
The repository source establishes the Domains API as an OpenAPI path family under apps/web/lib/openapi/domains/index.ts. That index does not implement each operation inline; instead, it imports operation definitions from dedicated modules and registers them under concrete HTTP paths. That design matters for API readers because the route family is intentionally grouped: listing and creating live at /domains, updating and deleting target /domains/{slug}, registration lives at /domains/register, and availability checks live at /domains/status. Sources: apps/web/lib/openapi/domains/index.ts
Official product documentation frames Dub as a link attribution platform for short links, conversion tracking, and affiliate programs. Domains are part of that short-link foundation: choosing the right domain affects the branded URL that customers, partners, and end users see. The docs also distinguish ordinary custom-domain management from domain registration, noting that registration availability is an Enterprise-only capability for certain customers. Treat registration routes as a specialized purchasing workflow, not as the normal way every workspace adds an already-owned custom domain.
Relevant Source Files
apps/web/lib/openapi/domains/index.ts— assembles the Domains OpenAPI path object and maps each route to the operation module that defines it.packages/cli/src/api/domains.ts— implements the CLI-side domain lookup helper, combining workspace domains from the Dub SDK with default Dub domains from the API.
Route Family and Operation Map
The OpenAPI index exports domainsPaths as a ZodOpenApiPathsObject, which is the source-level contract used to register this family with generated API documentation and tooling. The object has four route keys. /domains supports post for createDomain and get for listDomains. /domains/{slug} supports patch for updateDomain and delete for deleteDomain. /domains/register supports post for registerDomain. /domains/status supports get for checkDomainStatus. Sources: apps/web/lib/openapi/domains/index.ts
| Route | Method | Operation binding | Reader task |
|---|---|---|---|
/domains | GET | listDomains | List domains available to the workspace. |
/domains | POST | createDomain | Add a domain resource to the workspace. |
/domains/{slug} | PATCH | updateDomain | Modify settings for an existing domain identified by slug. |
/domains/{slug} | DELETE | deleteDomain | Remove or delete a domain resource identified by slug. |
/domains/register | POST | registerDomain | Register a purchasable domain through Dub’s supported registration flow. |
/domains/status | GET | checkDomainStatus | Check availability for one or more domains before registration. |
This map also clarifies the identifier used by update and delete operations. The route parameter is named slug, so clients should think of mutation-by-domain-slug rather than mutation-by-numeric-ID when using the public REST shape shown here. The CLI helper also treats domain identifiers as slugs: it maps each returned workspace domain to domain.slug, merges those strings with default-domain strings, and returns a de-duplicated slug list. That is a strong signal that domain selection in user-facing workflows is slug-oriented. Sources: packages/cli/src/api/domains.ts
Availability and Registration
Availability checking is represented by GET /domains/status through the checkDomainStatus operation binding. Official API documentation describes this endpoint as a way to check whether a domain name is available for purchase, including checking multiple domains at once. It also states that the current documented search is focused on .link domains. In practical client flows, call availability before presenting a registration confirmation or before attempting a purchase-like operation, especially when users enter candidate domains interactively.
Registration is represented separately as POST /domains/register. Keeping registration separate from ordinary creation is important. Creating a domain generally means adding a domain resource to the workspace, while registering a domain implies Dub is involved in provisioning or purchasing the name. Official docs call out that domain registration is only available for certain Enterprise customers, so clients should not assume every authenticated workspace can use this route successfully. A robust integration should expose the operation only when the workspace is eligible or handle authorization and eligibility failures clearly.
A typical registration-oriented flow starts with user input, then calls the status endpoint with one or more candidate domains, displays availability results, and only then submits to the register endpoint if the selected domain is available and the workspace has access. That sequencing keeps the user experience aligned with the public documentation and avoids treating registration as a generic create operation. It also leaves room for plan-gating, enterprise access checks, and domain-extension restrictions without changing the route family visible in the OpenAPI index. Sources: apps/web/lib/openapi/domains/index.ts
Create, List, Update, and Delete
The regular management path is /domains. GET /domains is bound to listDomains, and POST /domains is bound to createDomain. List operations power both API consumers and higher-level tools that need to show which domains can be used for new short links. Create operations are the entry point for adding a domain resource before it can be used in link-building workflows. Because the supplied index only shows operation bindings, clients should consult the generated OpenAPI schema for the exact request and response bodies when implementing these calls.
Update and delete operations are scoped to /domains/{slug}. The PATCH binding indicates partial mutation semantics for the domain identified by the slug, while the DELETE binding indicates removal of that domain resource through the same identifier. Official help documentation also describes an archive workflow in the dashboard: archived domains are hidden from active domain lists and the link builder, while existing links continue to work and remain visible in the links dashboard. That product behavior is useful context when deciding whether a user intends to archive, update visibility, or delete a domain entirely.
For integrators, the most important distinction is whether an action changes a domain’s configuration, removes it from active use, or affects the lifecycle of links that already use it. The public route map confirms that update and delete are both slug-targeted, but it does not collapse every domain-management action into deletion. When building admin interfaces, use list data to display the current domain set, use update for supported property changes, and reserve delete for intentional removal operations after a confirmation step. Sources: apps/web/lib/openapi/domains/index.ts
CLI and Default Domain Behavior
The CLI helper in packages/cli/src/api/domains.ts shows how command-line workflows discover domain choices. It starts by loading local configuration with getConfig, then constructs a Dub SDK client with token: config.access_token. With that authenticated client, it calls dub.domains.list(). In parallel, it issues a direct GET request to https://api.dub.co/domains/default with the same bearer token and a JSON content type. Sources: packages/cli/src/api/domains.ts
The helper then waits for both responses, parses the default-domain response with parseApiResponse<string[]>, and builds a combined list. Workspace domains are mapped to domain.slug, default domains are already strings, and the final return value is Array.from(new Set(allSlugs)). This means CLI consumers receive a de-duplicated array of usable domain slugs that includes both workspace-owned domains and Dub-provided default branded domains. Official docs describe default Dub domains such as dub.sh as automatically available to accounts, which explains why the CLI treats them as additional options rather than as custom-domain records returned by the normal domain list call.
This two-source lookup has an important integration lesson: the public Domains API family and user-facing domain choices are related but not identical. /domains lists workspace domain resources, while the CLI also asks for default domains through /domains/default. If you are recreating CLI-like behavior in another client, include default domains when the user’s task is choosing where a short link should live. If you are building an administrative domain-management screen, use the domain resource APIs for the workspace-owned or configured domain records. Sources: packages/cli/src/api/domains.ts
Compact Reference
| Concern | Concrete source-level name | Notes |
|---|---|---|
| OpenAPI export | domainsPaths | Exported as a ZodOpenApiPathsObject for generated API path registration. |
| List domains | GET /domains mapped to listDomains | Retrieves domain resources available through the Domains API family. |
| Create domain | POST /domains mapped to createDomain | Adds a domain resource through the standard management route. |
| Update domain | PATCH /domains/{slug} mapped to updateDomain | Mutates the domain identified by slug. |
| Delete domain | DELETE /domains/{slug} mapped to deleteDomain | Deletes or removes the domain identified by slug. |
| Register domain | POST /domains/register mapped to registerDomain | Specialized registration workflow; official docs describe registration as limited to certain Enterprise customers. |
| Check status | GET /domains/status mapped to checkDomainStatus | Availability check for one or more domains before registration. |
| CLI lookup | getDomains() | Authenticates with the stored access token, lists workspace domains, fetches default domains, and returns unique slugs. |
Use bearer-token authentication consistently when calling protected domain resources from tooling. The CLI implementation demonstrates the expected pattern for local clients: read an access_token from config, pass it to the official Dub SDK for supported SDK operations, and attach it as Authorization: Bearer ... when making a direct fetch to an API route that the helper consumes manually. That split is not unusual in a CLI package: SDK coverage can handle core resources while direct fetches fill in adjacent endpoints such as default-domain lookup. Sources: packages/cli/src/api/domains.ts
Implementation Notes and Next Steps
When adding or changing a Domains API operation, keep the OpenAPI path assembly and downstream clients aligned. A new route should be added to the domain path object only after its operation module defines the appropriate OpenAPI metadata. A changed identifier should be reflected everywhere that assumes slugs, including CLI selection flows that treat domain values as strings. A changed listing response should also be evaluated against getDomains(), because that helper explicitly reads domain.slug from each workspace domain returned by dub.domains.list(). Sources: apps/web/lib/openapi/domains/index.ts, packages/cli/src/api/domains.ts
For API consumers, start with the route family in this order: list current domains, include default domains if the user is choosing a short-link domain, create or update configured domains through /domains, check availability before any registration attempt, and treat registration as a gated capability. For deeper implementation work, read the generated API reference for exact schemas and then inspect the operation modules imported by apps/web/lib/openapi/domains/index.ts in the web app source tree.