Skip to content

REST API reference

Base URL

https://api.hee.la

All endpoints are versioned under /v1.

Authentication

Send your project token as a bearer header:

Authorization: Bearer hee_…

Issue tokens from the portal or POST /v1/portal/projects/{slug}/tokens.

Content type

All request/response bodies are JSON. Send Content-Type: application/json on every POST.

Rate limits

Per-IP limits apply to unauthenticated and auth endpoints. Authenticated control-plane calls are currently uncapped — fair-use applies.

Register a customer’s hostname. Idempotent — re-registering the same hostname in the same project returns the existing record with merged metadata.

Body parameters

FieldTypeRequiredDescription
hostnamestringyesFully-qualified domain name to route through Hee.
metadataobjectnoOpaque JSON blob returned verbatim from /resolve.

Request

Terminal window
curl -X POST https://api.hee.la/v1/edge/domains \
-H "Authorization: Bearer $HEE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"hostname": "docs.customer.com",
"metadata": { "workspaceId": "ws_abc123" }
}'

Response 200 OK

{
"hostname": "docs.customer.com",
"projectSlug": "acme-saas",
"verified": false,
"verifiedAt": null,
"createdAt": "2026-04-20T21:47:38.000Z",
"metadata": { "workspaceId": "ws_abc123" }
}

Errors

StatusMeaning
400hostname fails FQDN validation
402project is over its plan limit
409hostname is claimed by another project

List every domain owned by the token’s project.

Request

Terminal window
curl https://api.hee.la/v1/edge/domains \
-H "Authorization: Bearer $HEE_TOKEN"

Response 200 OK

[
{
"hostname": "docs.customer.com",
"projectSlug": "acme-saas",
"verified": true,
"verifiedAt": "2026-04-20T21:50:12.000Z",
"createdAt": "2026-04-20T21:47:38.000Z",
"metadata": { "workspaceId": "ws_abc123" }
},
{
"hostname": "app.customer.com",
"projectSlug": "acme-saas",
"verified": false,
"verifiedAt": null,
"createdAt": "2026-04-20T22:10:05.000Z",
"metadata": {}
}
]

Soft-delete a domain. Certificate and config are retained briefly so a re-add doesn’t re-trigger issuance rate limits.

Path parameters

FieldTypeRequiredDescription
hostnamestringyesURL-encoded FQDN to remove.

Request

Terminal window
curl -X DELETE https://api.hee.la/v1/edge/domains/docs.customer.com \
-H "Authorization: Bearer $HEE_TOKEN"

Response 204 No Content

Errors

StatusMeaning
404hostname is not owned by this project

Look up routing metadata for a hostname. Used by upstream apps that need to know which project (and which workspace, tenant, etc.) a request belongs to.

Query parameters

FieldTypeRequiredDescription
hostnamestringyesFQDN to resolve, unencoded in the query.

Request

Terminal window
curl "https://api.hee.la/v1/edge/resolve?hostname=docs.customer.com" \
-H "Authorization: Bearer $HEE_TOKEN"

Response 200 OK

{
"hostname": "docs.customer.com",
"projectSlug": "acme-saas",
"upstreamUrl": "https://acme.pages.dev",
"metadata": { "workspaceId": "ws_abc123" }
}
POST/v1/auth/request-magic-link

Email a signed magic-link to the user.

POST/v1/auth/callback

Exchange a magic-link token for a session cookie.

GET/v1/auth/me

Return the current session’s user record.

POST/v1/auth/sign-out

Invalidate the session cookie.

Request/response shapes live in the auth-user module.

POST/v1/portal/projects

Create a project.

GET/v1/portal/projects/{slug}

Get project details.

POST/v1/portal/projects/{slug}/tokens

Issue an API token. Returns the raw token once — store it immediately.

GET/v1/portal/projects/{slug}/tokens

List tokens (hashed preview only — raw values are never replayed).

DELETE/v1/portal/projects/{slug}/tokens/{tokenId}

Revoke a token.

POST/v1/portal/projects/{slug}/domains

Register a domain via the portal (mirrors the API-token path).

GET/v1/portal/projects/{slug}/domains

List domains for the project.

DELETE/v1/portal/projects/{slug}/domains/{hostname}

Remove a domain.

Unauthenticated liveness probe.

Response 200 OK

{ "status": "ok" }
Internal

Called by Caddy’s on_demand_tls hook to decide whether to issue a certificate. Returns 200 if the domain is registered, a 4xx otherwise. Not intended for external use and subject to change without notice.

Query parameters

FieldTypeRequiredDescription
domainstringyesFQDN to check.

A machine-readable OpenAPI 3.0 document is coming in Phase 2. Until then, this page and the TypeScript SDK types are the canonical reference.