LofentaLofenta/Docs

Reference

API reference

The Lofenta dashboard is powered by a small JSON API for projects and custom domains.


Authentication

Most dashboard routes under /api require an authenticated Lofenta session cookie. CLI routes under /api/cli also accept a bearer API key generated from the dashboard.

The cookie-backed routes are intended for first-party dashboard usage. External tooling should use the CLI auth flow instead of replaying browser cookies.

Response format

Successful responses return { ok: true, data: ... }. Error responses return { ok: false, code?, message }.

Success

{
  "ok": true,
  "data": { ... }
}

Error

{
  "ok": false,
  "code": "NOT_FOUND",
  "message": "Resource not found"
}

Projects

GET/api/projects

List all projects owned by the current user, newest first.

Response

{
  "ok": true,
  "data": [
    {
      "id": "proj_123",
      "name": "docs",
      "status": "running",
      "domain": null,
      "subdomain": "docs-a1b2c3",
      "gitRepo": "acme/docs",
      "gitBranch": "main",
      "createdAt": "2026-05-12T14:05:00.000Z",
      "updatedAt": "2026-05-12T14:07:00.000Z"
    }
  ]
}
POST/api/projects

Create a new project, reserve its generated subdomain, and queue the first deployment.

Request body

{
  "name": "Docs",
  "gitRepo": "acme/docs",
  "gitBranch": "main"
}

Response

{
  "ok": true,
  "data": {
    "id": "proj_123",
    "name": "Docs",
    "status": "idle",
    "subdomain": "docs-a1b2c3",
    "gitRepo": "acme/docs",
    "gitBranch": "main"
  }
}
name is required.
gitBranch defaults to main when omitted.
The subdomain is derived from the project name and a short ID suffix.
The new project starts in building status with an Initial deploy entry in its deployment history.
GET/api/projects/:id

Fetch a single project owned by the current user.

Response

{
  "ok": true,
  "data": {
    "id": "proj_123",
    "name": "Docs",
    "status": "running",
    "domain": "docs.example.com",
    "subdomain": "docs-a1b2c3",
    "gitRepo": "acme/docs",
    "gitBranch": "main"
  }
}
PATCH/api/projects/:id

Update editable project fields.

Request body

{
  "name": "Docs v2",
  "domain": "docs.example.com",
  "gitBranch": "release"
}

Response

{
  "ok": true,
  "data": {
    "id": "proj_123",
    "name": "Docs v2",
    "domain": "docs.example.com",
    "gitBranch": "release"
  }
}
Only fields included in the request body are updated.
updatedAt is refreshed automatically on every patch.
DELETE/api/projects/:id

Delete a project owned by the current user.

Response

204 No Content
Deleting a project also removes its deployments and domains through database cascades.

Deployments

GET/api/projects/:id/deployments

List recent deployments for a project owned by the current user.

Response

{
  "ok": true,
  "data": [
    {
      "id": "dep_123",
      "projectId": "proj_123",
      "status": "queued",
      "steps": [],
      "commitSha": null,
      "commitMessage": "Initial deploy",
      "createdAt": "2026-05-12T14:12:00.000Z",
      "finishedAt": null
    }
  ]
}
The response is limited to the 50 newest deployments.
POST/api/projects/:id/deployments

Queue a manual redeploy for a project owned by the current user.

Response

{
  "ok": true,
  "data": {
    "id": "dep_456",
    "projectId": "proj_123",
    "status": "queued",
    "steps": [],
    "commitMessage": "Manual redeploy"
  }
}
Active deployments for the same project are marked cancelled before the new deployment is queued.
The project status is updated to building.

Domains

GET/api/domains

List custom domains attached to all projects owned by the current user.

Response

{
  "ok": true,
  "data": [
    {
      "id": "dom_123",
      "projectId": "proj_123",
      "domain": "docs.example.com",
      "sslStatus": "pending",
      "verified": false,
      "createdAt": "2026-05-12T14:10:00.000Z"
    }
  ]
}
POST/api/domains

Attach a custom domain to one of the current user's projects.

Request body

{
  "projectId": "proj_123",
  "domain": "docs.example.com"
}

Response

{
  "ok": true,
  "data": {
    "id": "dom_123",
    "projectId": "proj_123",
    "domain": "docs.example.com",
    "sslStatus": "pending",
    "verified": false
  }
}
projectId and domain are required.
The API normalises the domain by lowercasing it and stripping http:// or https://.
Duplicate domains return HTTP 409.
DELETE/api/domains/:id

Remove a custom domain from a project owned by the current user.

Response

{
  "ok": true
}

Status values

Project status

idleenum
buildingenum
runningenum
failedenum
stoppedenum

Deployment status

queuedenum
cloningenum
installingenum
buildingenum
startingenum
health_checkenum
liveenum
failedenum
cancelledenum

CLI endpoints

Auth via Authorization: Bearer <cli_token> (generated from Dashboard › Settings › CLI access). All endpoints are stable v0.4.

GET/api/cli/meConnected user info (id, email, plan)
GET/api/cli/usagePlan limits + current consumption (services, domains, build minutes, storage)
GET/api/cli/templatesAvailable project templates with min plan + requirements
GET/api/cli/projectsList your projects with last deploy status
GET/api/cli/projects/{idOrName}One project with recent deployments + domains
POST/api/cli/deployCreate a project or trigger a deploy by repo/template
POST/api/cli/projects/{idOrName}/redeployTrigger a fresh deploy on an existing project
POST/api/cli/projects/{idOrName}/restartRestart the running container without rebuilding
POST/api/cli/projects/{idOrName}/rollbackBody { "deploymentId"?: string } - revert to a prior live deployment
GET/api/cli/projects/{idOrName}/deploymentsRecent deployments per plan retention
GET/api/cli/projects/{idOrName}/logsLive tail of the latest deploy log (Server-Sent Events)
GET/api/cli/projects/{idOrName}/tailLive tail of container stdout/stderr (Server-Sent Events)
POST/api/cli/projects/{idOrName}/execBody { "command": "ls /app", "user"?: "root" } - one-shot docker exec
GET/api/cli/projects/{idOrName}/envList env vars (values returned to authed CLI)
PATCH/api/cli/projects/{idOrName}/envBody { "set": [{key,value}], "remove": [key] } - merge env updates
GET/api/cli/projects/{idOrName}/domainsList custom domains + DNS records needed
POST/api/cli/projects/{idOrName}/domainsBody { "domain": "app.example.com" } - attach a custom domain
DELETE/api/cli/projects/{idOrName}/domains?domain=xDetach a custom domain
GET/api/cli/projects/{idOrName}/snapshotsList DB snapshots (postgres/mariadb projects)
POST/api/cli/projects/{idOrName}/snapshotsBody { "label"?: string } - take a new DB snapshot
POST/api/cli/projects/{idOrName}/snapshots/{id}/restoreRestore a snapshot into the running database
GET/api/cli/projects/{idOrName}/servicesLinked internal services (Postgres/Redis/etc) + candidates
GET/api/cli/projects/{idOrName}/volumesNamed Docker volumes attached to a project

Quick examples

List your projects:

curl -H "Authorization: Bearer $LOFENTA_TOKEN" \
  https://lofenta.com/api/cli/projects

Trigger a redeploy on an existing project:

curl -X POST -H "Authorization: Bearer $LOFENTA_TOKEN" \
  https://lofenta.com/api/cli/projects/my-app/redeploy

Run a one-shot command in the running container:

curl -X POST -H "Authorization: Bearer $LOFENTA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command":"node --version"}' \
  https://lofenta.com/api/cli/projects/my-app/exec

Bulk import env vars from a local .env:

lofenta env import my-app .env
# or via raw API
curl -X PATCH -H "Authorization: Bearer $LOFENTA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"set":[{"key":"DATABASE_URL","value":"..."}]}' \
  https://lofenta.com/api/cli/projects/my-app/env

Current limits

  • Source upload from the CLI (deploy --from-dir) is not exposed yet. Git-based or template-based deploys are the supported paths.
  • WebSocket transports are not part of the public API. Logs and container tail use Server-Sent Events.
  • Per-token rate limit is 600 requests per minute. Exec endpoint additionally caps stdout at 256 KiB and runtime at 30s.

Next

Introduction

Back to the docs overview