The Olibato REST API is available at /v/api/v1/ when enabled for a deployment.
It exposes the sites model used by the browser: reserve sites, create deploys,
inspect versions and events, operate runtimes, manage access and custom domains,
and read usage. App templates are machine-readable so an agent can discover
supported parameters before installing one.
Operators enable the interface with OLIBATO_REST_API_ENABLED=true. Production
deployments must also set an independent high-entropy
OLIBATO_API_TOKEN_PEPPER; throttles use the shared Redis cache so limits apply
across web workers.
Register and create a personal access token#
An API-only client can complete signup and mailbox verification without a browser:
GET /v/api/v1/auth/registration
POST /v/api/v1/auth/registration
POST /v/api/v1/auth/registration/verify
The registration request includes username for the permanent personal
namespace, email, password, and the legal versions returned by the first
request. Verification activates the account and returns an initial owner token
once. Verification and recovery secrets are single-use and delivered only to
the registered mailbox.
Authenticated owners manage credentials at /account/tokens. Tokens have one
ordered permission: read, write, or owner. Write includes read; owner adds
credential management and irreversible operations. Organization roles remain an
independent authorization boundary.
Send the token as a bearer credential:
Authorization: Bearer oli_pat_…
See API tokens for safe storage, inspection, recovery, and revocation.
Personal and organization namespaces#
Personal site requests use the caller's permanent namespace. Organization
requests include the organization slug where the operation supports it. A
request for an organization the token owner cannot access returns 404; API
requests never depend on the dashboard's currently selected workspace.
Reserve and inspect sites#
Use the primary site collection and detail resources:
GET|POST /v/api/v1/sites
GET|PATCH|DELETE /v/api/v1/sites/{site_slug}
GET /v/api/v1/sites/{site_slug}/status
GET /v/api/v1/sites/{site_slug}/logs
GET /v/api/v1/sites/{site_slug}/usage
Creating a site reserves its slug and namespaced host before a deploy exists.
state: running reports runtime state, and active_version_id identifies the selected
version. host_url is the intended public address constructed from the site namespace;
its presence does not verify DNS provisioning, certificate installation, or public HTTPS
reachability. The additive https status below supplies bounded, timestamped proof.
Verify trusted HTTPS and expected application content separately before reporting a
public deployment complete.
GET /sites/{site_slug}/logs returns build logs, build-step events and runtime
state/error metadata; it is not a live application stdout/stderr stream. Treat logs
as potentially sensitive and summarize them before sharing. The CLI supports
status HOST, status HOST --deploy ID, and logs HOST; usage is currently a
public API read, without a dedicated CLI command.
Site deletion removes its runtime and route while preserving append-only usage records required for audit.
Create deploys#
Deploy a container image, repository revision, local source upload, or app template through the site's deploy collection. Follow the returned build and version through the detail, event, and manifest resources:
POST /v/api/v1/sites/{site_slug}/source-uploads
GET|POST /v/api/v1/sites/{site_slug}/deploys
GET /v/api/v1/sites/{site_slug}/deploys/{deploy_id}
GET /v/api/v1/sites/{site_slug}/deploys/{deploy_id}/events
GET /v/api/v1/sites/{site_slug}/deploys/{deploy_id}/manifest
POST /v/api/v1/sites/{site_slug}/deploys/{deploy_id}/actions/{action}
Local source uploads accept committed archives and return an upload ID for the deploy request. Source bytes are temporary; source-free identity and build evidence remain after the deploy reaches a terminal state.
Discover supported app templates and their parameter schemas through:
GET /v/api/v1/app-templates
GET /v/api/v1/app-templates/{template_slug}
Access and domains#
Set HTTP access to public or authenticated, and create expiring source-IP
grants for private TCP services:
GET|PATCH /v/api/v1/sites/{site_slug}/access
GET|POST /v/api/v1/sites/{site_slug}/tcp-access
Custom-domain creation returns the required ownership TXT and traffic CNAME records. Verification must observe both public records before routing and certificate issuance begin:
GET|POST /v/api/v1/sites/{site_slug}/domains
GET|DELETE /v/api/v1/sites/{site_slug}/domains/{domain}
POST /v/api/v1/sites/{site_slug}/domains/{domain}/verify
Safe writes#
JSON creation and action POST requests require an Idempotency-Key header.
Repeating the same request with the same key replays its stored response; using
the key with different input returns 409. Streamed source upload uses its
canonical SHA-256 as content identity, and the returned upload ID is supplied to
the idempotent deploy request.
Mutable resources return an ETag. Send that value in If-Match for PATCH
and DELETE; missing preconditions return 428 and stale values return 412.
curl -sS https://olibato.com/v/api/v1/sites \
-H "Authorization: Bearer $OLIBATO_API_TOKEN"
Errors use application/problem+json with RFC 9457 fields, a stable code,
request correlation ID, and optional field errors. Lists use opaque cursor
pagination with next, previous, and results.
OpenAPI source of truth#
The canonical OpenAPI 3.1 document lists supported routes, exact request and response schemas, permissions, idempotency rules, and concurrency preconditions. Agents should use that document for interface discovery rather than inferring routes from browser pages.
Regenerate and validate the checked-in artifact after changing the REST surface:
cd web
python3 manage.py spectacular \
--urlconf olibato_api.urls \
--format openapi-json \
--file ../docs/api/openapi.json \
--validate
Usage totals and accounting availability#
GET /v/api/v1/sites/{site_slug}/usage adds an accounting object.
GET /v/api/v1/organizations/{organization_slug}/usage adds the same object
inside summary. Existing numeric totals and access requirements are unchanged.
Those numbers aggregate recorded ledger entries: zero is not evidence of zero
actual consumption, and nonzero is not a complete-history guarantee.
accounting.basis is recorded_ledger; history_complete is currently false.
collection.instances counts only the authorized scope's missing, unavailable,
stale, fresh and binding_mismatch checkpoints. freshness_window_seconds is
60, matching the existing collector's observation bound. all_fresh means every
scoped instance has a recent successful observation; it does not erase gaps,
prove uninterrupted sampling, or establish complete monthly usage. No instances
means all_fresh: false, not proof that collection occurred.
reasons contains finite public reason codes, including retained stream/event
and observation gaps. Raw checkpoint data, node addresses and identities from
other namespaces are not returned. storage.availability remains unavailable,
interval_coverage is unproven, and new_interval_metering is disabled.
The existing storage_gb_hours field retains its numeric contract and historical
values; its unit is GiB-hours (1024³ bytes × hours). This metadata does not change
quota enforcement, rates, ledger records or authorize backfill. API clients must
not present recorded totals as fully measured consumption or guaranteed remaining
capacity when accounting coverage is unavailable/incomplete.
HTTPS readiness (additive field)#
Site detail/list/status and activation responses now include https separately
from application state and the intended host_url:
{"state":"running","https":{"state":"ready","reason":"trusted_https_verified","retryable":false,"verified_at":"2026-09-13T17:25:51Z","valid_until":"2026-09-13T17:30:51Z"}}
https.state is preparing, ready, failed, or unknown. ready means a
recent bounded public-DNS, trusted TLS, exact namespace certificate and content
comparison against the selected node's owned Host route passed. This is an
observation, not an uptime guarantee. Proofs expire after five minutes and become
unknown if the runtime/version binding changes. Missing proof is unknown,
not success. Numeric usage and ordinary runtime state are unchanged.
After the normal build succeeds, explicitly activate it through the existing API. Personal activation queues scoped follow-through; do not infer activation from build completion. The background worker observes only those new operation bindings, enrolls through private mTLS, and uses the existing guarded DNS/ACME path when platform order authority is available. Operators configure node/edge trust once; customers never supply upstream addresses or use SSH.
Use bounded status reads. Preserve operation/idempotency receipts; an HTTPS
failure does not justify creating another deploy or order. Safe reasons include
runtime_pending, node_not_enrolled, new_order_authority_exhausted,
public_dns_not_ready, public_routing_not_ready, proof_stale, and
runtime_binding_changed. Follow retryable; there is no public DNS/issuance
retry bypass. Current new-order allocation is zero because the authorized test
budgets have been consumed; this is reported as a gate, not HTTPS readiness.
The source CLI supports status hello --namespace personal --require-https:
it prints normal JSON and exits nonzero unless HTTPS proof is fresh and ready.
Without the flag, status remains backward compatible. --deploy reports a build,
so it cannot be combined with --require-https. No CLI package was published.