Skip to content
repoless

API & tokens

Programmatic deploys, ingest, and integrations.

Repoless ships REST endpoints for everything you can do in the UI. Authentication is bearer-token; the prefix tells you what kind of token it is.

Tokens at a glance

  • dwa_* — Pier API tokens. Scoped bearer tokens for programmatic access to deploys, apps, hosts, databases.
  • dwb_* — Bootstrap tokens. One-time, consumed by /v1/agent/register and exchanged for a long-lived host token.
  • dwh_* — Host tokens (Pier). Long-lived, stored on the host at /etc/deploywatch/agent.env. Used by the agent to talk to the control plane.
  • lwh_* — Ingest tokens (Beacon). Authorize log ingest from a host or service.
  • LOGWATCH_TOKEN — Beacon CLI session token. Saved at ~/.logwatch/token after running logwatch login.

Encryption at rest

All tokens stored in our D1 are encrypted with WebCrypto AES-GCM using ENV_KEY. Only their hashes are compared at request time.

Pier API tokens

Mint under Account → API tokens. Each token has a label, an optional expiry, and a scope set. Scopes follow resource:action form:

  • apps:read, apps:deploy
  • hosts:read, hosts:write
  • projects:read, projects:write
  • services:* (managed databases)
shell
$ curl https://pier.repoless.com/api/admin/apps/<id>/deploy \
    -X POST \
    -H "Authorization: Bearer dwa_•••••"

Host tokens

The Pier install script exchanges a bootstrap token for a host token and writes it to /etc/deploywatch/agent.env. The agent uses that token for every subsequent request — heartbeat, job polling, log forwarding.

Rotate host tokens from Admin → Servers → ⋯ → Rotate token; the existing agent picks up the new token on next heartbeat.

Ingest tokens (Beacon)

Mint host ingest tokens from /admin/hosts → Add host. Each token is scoped to a tenant. The Pier agent uses a per-tenant ingest token automatically; Vector configs you maintain by hand reference one explicitly.

GitHub webhooks

Configure your repo with a webhook pointing at https://pier.repoless.com/v1/deploy/webhook/github. Each app generates its own HMAC secret — sign the webhook payload with it.

  • Push to main: triggers a deploy of the matched app.
  • Pull request opened/synchronized: spins up a PR preview environment.
  • Pull request closed: tears the preview down.

Rotate the HMAC secret from App → Webhook. Old secrets are accepted for a 60-second grace window so an in-flight push doesn't race with rotation.

Pier endpoints

All Pier API endpoints live under /api/admin/* and require an Authorization: Bearer dwa_* header. Selected endpoints:

  • GET /api/admin/apps/:id
  • POST /api/admin/apps/:id/deploy
  • POST /api/admin/apps/:id/exec — run a command in the running container
  • GET /api/admin/apps/:id/cost
  • GET /api/admin/apps/:id/stats
  • GET /api/admin/apps/:id/uptime
  • POST /api/admin/apps/:id/limits
  • GET/POST /api/admin/apps/:id/runbooks/:rbId
  • POST /api/admin/managed/:id/snapshot

Beacon endpoints

  • POST /v1/logs/ingest — gzip NDJSON, host-token bearer.
  • GET /api/search — full-text search with filters.
  • POST/DELETE /api/collections/*
  • GET/POST/DELETE /api/alerts/*
  • POST /api/aliases/upsert

Errors

All endpoints return JSON. Errors carry a structured body:

json
{
  "error": "not_found",
  "message": "App not found",
  "details": { "id": "app_abc123" }
}
  • 400 — validation error
  • 401 — missing/invalid token
  • 403 — token lacks scope or tenant access
  • 404 — resource not found
  • 409 — conflict (e.g. duplicate slug)
  • 429 — rate limit hit

Rate limits

  • /api/auth/* — per-IP, conservative (prevents OTP brute-force).
  • /api/admin/* — per-token, generous. Burst above limit returns 429 with retry-after.
  • /v1/logs/ingest — body-size and decompression-ratio gated rather than per-IP.