olibato Documentation
Browse documentation

REST API guide for agents

Exact authentication, site creation, deployment, status, logs, and deletion requests for an API client with no prior serverl3ss context.

Status
canonical
Audience
Software agents and API clients
Updated
serverl3ss REST API guide for agents#

Use the control-plane REST API at https://olibato.com/v/api/v1. Hosted app URLs remain under serverl3ss.com; do not send control-plane tokens to app hosts. Send a personal access token on every non-registration request:

Authorization: Bearer oli_pat_...
Content-Type: application/json

Create tokens in Account → API tokens. A read token can inspect resources, a write token can create sites and deploy, and an owner token is required to delete a site. Mutations documented with Idempotency-Key require a stable caller-generated value. Repeating the same request with the same key replays the stored response; changing the request returns 409 idempotency-conflict.

Destination-aware replay binds site requests to the authorized site/namespace identity and canonical query parameters. Omitting namespace, using personal, or using your username resolves to the same personal site. Query-key order does not matter; changing a destination, query value or body does. Tenant access is checked before site replay.

Receipts from before destination-aware replay cannot prove their original query. They are retained but return 409 idempotency-legacy-reconciliation-required, including when the caller believes the retry is identical. Inspect the original resource/deployment and its outcome before making any new submission; do not rotate the key or wait out its expiry merely to bypass this response. The upgrade does not rewrite receipts or reconstruct missing destination evidence.

For CLI deployment, supply a unique --idempotency-key per deployment intent and retain it until the outcome is known. If omitted, the CLI prints the generated key before submitting the build. After a timeout or unreadable response, inspect the site's deploy list/status first; retry only the identical request with the same key within the API's 24-hour retention window. Do not use a new key to recover an uncertain submission. Keys must not contain secrets and must be unique across sites and namespaces. After retention expires, reconcile before submitting anything again.

Local source uploads use a stable filename and a key scoped to destination, commit, branch and archive contents. The CLI prints the returned upload UUID; retain it and use --upload-id UUID when recovering a deployment instead of archiving a potentially changed worktree. This cannot recover the identity of an upload made with an older CLI's random filename: inspect existing uploads before retrying those requests with the repaired CLI.

status HOST --deploy ID and logs HOST are single reads; the CLI does not poll or activate automatically. Bound any caller polling deadline and space requests at least two seconds apart. A successful build still requires the activation API below, followed by runtime status and app-content verification. Updates use a new deployment intent and the same build-then-activate sequence.

Five-minute container flow#

Set the API URL and token without putting the token in shell history:

API=https://olibato.com/v/api/v1
read -rsp 'PAT: ' TOKEN; export TOKEN

Create a site in the personal namespace. Omit host to derive it from name.

curl -sS "$API/sites" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: quickstart-site-1' \
  -d '{"name":"Agent web","host":"agent-web","access":"public"}'

Deploy a versioned container and ask the build agent to author deploy.yaml:

curl -sS "$API/sites/agent-web/deploys" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: quickstart-deploy-1' \
  -d '{"source":"container","image":"docker.io/library/nginx:1.27","agent":true}'

Poll the returned deploy id until status is succeeded or terminal:

curl -sS "$API/sites/agent-web/deploys/DEPLOY_ID" -H "Authorization: Bearer $TOKEN"

Activate the successful deploy. Activation starts or replaces the site runtime and preserves exactly one active version:

curl -sS -X POST "$API/sites/agent-web/deploys/DEPLOY_ID/actions/activate" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: quickstart-activate-1' \
  -d '{}'

Check site state, inspect logs, and open the returned host_url when state becomes running:

curl -sS "$API/sites/agent-web/status" -H "Authorization: Bearer $TOKEN"
curl -sS "$API/sites/agent-web/logs" -H "Authorization: Bearer $TOKEN"
curl -i https://agent-web.USERNAME.serverl3ss.com

Delete the site with an owner token. This soft-deletes control-plane metadata and submits teardown for any live runtime:

curl -sS -X DELETE "$API/sites/agent-web" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: quickstart-delete-1' \
  -d '{}'

Namespaces and host conflicts#

Sites use global /sites URLs. namespace is a JSON field on create and a query parameter on reads, updates, deploys, and deletion. It defaults to the caller's personal namespace. Supply an organization slug for an organization site, for example POST /sites with "namespace":"acme", then use ?namespace=acme on the site-scoped URLs.

Your personal source workspace is provisioned automatically during signup and repaired automatically if it is ever missing. Personal-site deploys are always attributed and billed to that deterministic workspace, regardless of which team workspace is currently selected; organization-site deploys remain attributed to the site's organization. No workspace setup action is required.

Check a host before creation with GET /host-availability?host=web1&namespace=personal. A taken or reserved host returns HTTP 409 with a stable code and a reason. Creation performs the same check atomically. Quota failures return HTTP 429 and a stable quota code.

Deployment sources#

POST /sites/{slug}/deploys accepts exactly one source shape:

{"source":"container","image":"docker.io/library/nginx:1.27","manifest":{"version":1,"build":{"steps":[]},"run":{"image":"docker.io/library/nginx:1.27","port":80}}}
{"source":"repository","repo":"owner/name","ref":"main","manifest_path":".olibato/deploy.yaml"}

The GitHub repository must first be connected and reviewed in the namespace's source workspace. Private repositories use the existing GitHub App installation.

For local code, upload a committed ZIP or tar archive as multipart form data to /sites/{slug}/source-uploads with source, commit_sha, and optional branch. Then deploy it:

{"source":"source_upload","upload_id":"UPLOAD_UUID"}

Install a curated app after enumerating /app-templates and reading its params_schema:

{"source":"app_template","template":"postgresql","version":"16","params":{"database":"app","username":"app","resource_size":"small"}}

For container, repository, and source-upload deployments, provide an embedded manifest, rely on the source tree's manifest_path, or set "agent":true. Supplied and agent-authored manifests enter the same validation, isolated build, security scan, and version pipeline.

Deploy inspection and actions#

  • GET /sites/{slug}/deploys lists deploy attempts.
  • GET /sites/{slug}/deploys/{id} returns status.
  • GET /sites/{slug}/deploys/{id}/events streams text/event-stream build milestones.
  • GET /sites/{slug}/deploys/{id}/manifest returns the supplied or resolved manifest.
  • POST /sites/{slug}/deploys/{id}/actions/cancel cancels an active attempt.
  • POST /sites/{slug}/deploys/{id}/actions/retry retries a terminal GitHub attempt.
  • POST /sites/{slug}/deploys/{id}/actions/activate selects a successful version and starts the site.

Custom domains#

Attach a single hostname after the site has an active deploy. Wildcards are not accepted. The response contains the exact TXT ownership record and CNAME traffic record in dns.records:

curl -sS -X POST "$API/sites/agent-web/domains" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: agent-web-domain-1' \
  -d '{"domain":"app.example.com"}'

Publish both returned records at the domain's DNS provider. If Cloudflare hosts the zone, keep the CNAME DNS-only (grey cloud). Do not proxy it through Cloudflare. An A record whose value is the returned edge IP may replace the CNAME where the DNS provider cannot use a CNAME.

After public DNS sees both records, request verification:

curl -sS -X POST "$API/sites/agent-web/domains/app.example.com/verify" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: agent-web-domain-verify-1' \
  -d '{}'

pending means DNS has not propagated or the edge target is missing. failed includes an actionable verification or certificate error. verified means ownership and traffic records passed; Certbot HTTP-01 issuance is queued. Poll GET /sites/agent-web/domains/app.example.com until both the domain and certificate are active/issued, then open https://app.example.com.

Remove the router alias and withdraw its dedicated certificate with:

curl -sS -X DELETE "$API/sites/agent-web/domains/app.example.com" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: agent-web-domain-delete-1' \
  -d '{}'

For an organization site, add ?namespace=ORGANIZATION_SLUG to every site-domain URL.

Site and TCP access#

Switch an HTTP site between public and signed-in-only access with a write token. Anonymous traffic to an authenticated site is redirected before the runtime wakes:

curl -sS -X PATCH "$API/sites/agent-web/access" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: agent-web-private-1' \
  -d '{"access":"authenticated"}'

Private TCP services use temporary source-IP grants. Name a non-public service from the active deploy manifest and choose a duration from 1 to 1440 minutes:

curl -sS -X POST "$API/sites/agent-web/tcp-access" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: agent-web-db-access-1' \
  -d '{"service":"database","duration_minutes":60}'

The response includes connection, cidr, and expires_at. Connect from the reported CIDR before expiry; the edge rejects other sources and self-expires the grant without waking the site.

Endpoint index#

  • Account and namespaces: GET /account, GET /organizations.
  • Sites: GET|POST /sites, GET|PATCH|DELETE /sites/{slug}, PATCH /sites/{slug}/access, POST /sites/{slug}/tcp-access, GET /host-availability.
  • Local code: GET|POST /sites/{slug}/source-uploads.
  • Deploys: GET|POST /sites/{slug}/deploys, deploy detail, events, manifest, and actions listed above.
  • Operations: GET /sites/{slug}/status, GET /sites/{slug}/logs.
  • Custom domains: GET|POST /sites/{slug}/domains, GET|DELETE /sites/{slug}/domains/{domain}, POST /sites/{slug}/domains/{domain}/verify.
  • App registry: GET /app-templates, GET /app-templates/{slug}.
  • Legacy organization build and dashboard endpoints remain available for dashboard compatibility.

The complete machine-readable contract is at /v/docs/api/openapi.json.

Errors and rate behavior#

Errors use application/problem+json with status, detail, stable code, request_id, and optional field-level errors. Treat 409 as a state or identity conflict, 412 as stale optimistic concurrency, 429 as quota or rate admission, and 503 as a temporary dependency failure. Honor Retry-After when present. Build and write endpoints are rate-limited independently; poll deploy status no faster than every two seconds and use the events stream when practical.