Skip to content

Domains

Manage the domains a HappyView instance serves. Each domain gets its own atproto OAuth client identity. The primary domain is set from PUBLIC_URL on first boot. All endpoints require the settings:manage permission.

On an instance run by a managed-hosting platform (one with PLATFORM_API_KEY_HASH set, which GET /config reports as platform_managed), the platform decides which hostnames reach the instance and which one is its public URL. There, adding, deleting and making a domain primary accept only the platform’s key, and answer 403 to everyone else, an operator with superadmin included. Listing domains still accepts settings:manage.

const TOKEN = "hv_..."; // your API key
const headers = { Authorization: `Bearer ${TOKEN}` };
GET /admin/domains
interface Domain {
id: string;
url: string;
is_primary: boolean;
created_at: string;
updated_at: string;
}
const response = await fetch("http://127.0.0.1:3000/admin/domains", {
headers,
});
const data: Domain[] = await response.json();

Response: 200 OK

[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://gamesgamesgamesgames.games",
"is_primary": true,
"created_at": "2026-04-16T00:00:00Z",
"updated_at": "2026-04-16T00:00:00Z"
}
]
POST /admin/domains
interface Domain {
id: string;
url: string;
is_primary: boolean;
created_at: string;
updated_at: string;
}
const response = await fetch("http://127.0.0.1:3000/admin/domains", {
method: "POST",
headers: {
...headers,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://api.example.com",
}),
});
const data: Domain = await response.json();
FieldTypeRequiredDescription
urlstringyesValid origin (scheme + host, no path or trailing slash). Must be https unless PUBLIC_URL is a loopback address.

Returns 400 Bad Request if the URL is invalid or already registered.

Response: 201 Created

{
"id": "550e8400-e29b-41d4-a716-446655440001",
"url": "https://api.example.com",
"is_primary": false,
"created_at": "2026-04-16T00:00:00Z",
"updated_at": "2026-04-16T00:00:00Z"
}

Also builds an OAuth client for the domain and updates the in-memory cache.

DELETE /admin/domains/{id}
await fetch("http://127.0.0.1:3000/admin/domains/550e8400-e29b-41d4-a716-446655440001", {
method: "DELETE",
headers,
});

Returns 400 Bad Request if the domain is the primary domain (make another domain primary first), or if it’s the instance’s only domain. Returns 404 Not Found if the domain doesn’t exist.

Response: 204 No Content

Also removes the domain’s OAuth client and cache entry.

POST /admin/domains/{id}/primary
await fetch("http://127.0.0.1:3000/admin/domains/550e8400-e29b-41d4-a716-446655440001/primary", {
method: "POST",
headers,
});

Sets the target domain as the primary. Unsets the current primary in a single operation. Returns 404 Not Found if the domain doesn’t exist.

Response: 204 No Content

Also updates the in-memory cache and primary client reference.