Skip to content
chalupa
How it worksSecurityDocumentation
Open console
Menu
How it worksSecurityDocumentationOpen console
chalupa

Operational signal for ephemeral environments. Compute can be torn down while persistent data follows its own lifecycle.

Product

How it worksSecurityConsole

Learn

QuickstartConceptsAPI and schema

Built for ephemeral operations, not forgotten resources.

All displayed costs are estimates.

Documentation/API and schema
/

Start here

QuickstartSecrets with tvault

Operating model

Conceptschalupa.yml referenceLifecycleTunnels and securityData and seeds

Control plane

Control plane and agentSuites and artifactsCosts and idle observation

Reference

Private operationsTroubleshootingAPI and schema
Browse documentation
/

Start here

QuickstartSecrets with tvault

Operating model

Conceptschalupa.yml referenceLifecycleTunnels and securityData and seeds

Control plane

Control plane and agentSuites and artifactsCosts and idle observation

Reference

Private operationsTroubleshootingAPI and schema

Reference

API and schema

v1 contracts for heartbeats, events, suite runs, and authenticated fleet reads.

Reviewed 2026-07-23

The API separates ingest from reads. Ingest endpoints use HMAC; read endpoints accept an administrator session or a valid Bearer token.

Endpoints

Method Path Auth Purpose
POST /api/ingest HMAC Agent heartbeat.
POST /api/ingest/events HMAC Batch of explicit events.
POST /api/ingest/runs HMAC Results and artifacts.
GET /api/fleet admin Aggregated fleet view.
POST /api/auth/login token in body Creates an HttpOnly cookie.
POST /api/auth/logout none Clears the cookie if present.
GET /api/health none Minimal process liveness.
GET /api/ready cron Bearer Redacted runtime and database readiness.
GET /api/cron/costs cron Bearer Provider inventory reconciliation and estimated cost snapshots.
GET /api/cron/retention cron Bearer Expired heartbeat and nonce pruning.

Writes are disabled while Chalupa runs in demo mode.

Ingest authentication

Required headers:

content-type: application/json
x-chalupa-timestamp: <epoch-seconds>
x-chalupa-nonce: <unique-value>
x-chalupa-signature: v1=<hmac-sha256-hex>

Canonical string:

v1
<METHOD>
<PATH>
<TIMESTAMP>
<NONCE>
<SHA256_HEX_OF_BODY>

The signature uses CHALUPA_INGEST_KEY, which must contain 32 to 1024 bytes with no leading or trailing whitespace or line breaks. The timestamp allows a limited window, and each nonce is claimed exactly once.

Heartbeat

{
  "version": "1",
  "environmentSlug": "demo-harbor",
  "environmentName": "Demo Harbor",
  "observedAt": "2026-07-23T18:20:00.000Z",
  "deployment": {
    "provider": "digitalocean",
    "providerId": "10001",
    "region": "nyc3",
    "sizeSlug": "s-2vcpu-4gb",
    "launchedAt": "2026-07-23T17:50:00.000Z"
  },
  "ip": "192.0.2.44",
  "uptimeSeconds": 1800,
  "containers": [
    {
      "name": "api",
      "state": "running",
      "memoryMiB": 312,
      "cpuPercent": 4.8
    }
  ],
  "reaper": {
    "idleChecks": 2,
    "checkIntervalSeconds": 300,
    "limitMinutes": 45
  },
  "disk": {
    "mountedGiB": 20,
    "usedGiB": 1.4
  },
  "agentVersion": "1"
}

Accepted response:

{
  "accepted": true
}

The server can include additional counters or identifiers.

Events

{
  "version": "1",
  "environmentSlug": "demo-harbor",
  "deploymentProviderId": "10001",
  "deployment": {
    "provider": "digitalocean",
    "sizeSlug": "s-2vcpu-4gb",
    "region": "sfo3",
    "dropletHourlyUsd": 0.04167,
    "volumeGiB": 10
  },
  "events": [
    {
      "sourceEventId": "evt_demo_launched_001",
      "occurredAt": "2026-07-23T17:50:00.000Z",
      "kind": "launched",
      "reason": "manual"
    }
  ]
}

deployment is required when the payload includes launched and is rejected when the payload has no launch event. It captures the bounded provider metadata and launch-time rate needed to account for a short-lived deployment before the next inventory poll; it never carries a provider credential.

Supported kinds:

  • launched;
  • sunk;
  • reaper-warning;
  • reaper-destroyed;
  • seed-restored;
  • heartbeat-recovered.

Supported reasons are manual, idle, provider, health, seed, and unknown.

Suite runs

{
  "version": "1",
  "environmentSlug": "demo-harbor",
  "suiteName": "checkout-e2e",
  "runs": [
    {
      "sourceRunId": "run_demo_20260723_001",
      "specName": "create-order",
      "status": "passed",
      "durationMs": 18420,
      "metricName": "workflow-latency",
      "metricMs": 1220,
      "variant": "baseline",
      "artifacts": [
        {
          "kind": "report",
          "store": "fcheap-local",
          "stashId": "stash_demo_report_001"
        }
      ]
    }
  ]
}

A request accepts up to 250 runs; each run accepts up to 20 artifacts. The server validates limits, enum values, and duplicates before persisting data.

Fleet

GET /api/fleet returns:

{
  "mode": "demo",
  "generatedAt": "2026-07-23T18:21:00.000Z",
  "totals": {
    "environments": 1,
    "afloat": 1,
    "stale": 0,
    "sunk": 0,
    "unknown": 0,
    "estimatedHourlyUsd": 0.04,
    "estimatedMonthToDateUsd": 0.62
  },
  "environments": []
}

IP addresses, names, and stack details belong only to the authenticated response. Public metadata does not include them.

Operational probes

GET /api/health is an unauthenticated liveness probe. It returns only:

{ "status": "ok" }

GET /api/ready validates the runtime contract and, in database mode, runs a bounded database probe. It requires Authorization: Bearer <CRON_SECRET> and returns { "status": "ready" }, or a redacted 503 response. Neither endpoint returns configuration, provider inventory, or fleet data.

Login

URL-encoded form:

token=<admin-token>
next=/app

next is optional and accepts only relative paths that begin with /, never //. Successful authentication creates the chalupa_admin HttpOnly cookie.

Do not send the token in a query string.

Errors

The API uses semantic HTTP status codes:

Code Case
202 Ingest accepted.
400 Malformed JSON.
401 Invalid session or signature.
409 HMAC nonce already claimed, or deployment assigned to another environment.
413 Body exceeds the endpoint limit.
422 Invalid content type, UTF-8, or schema.
503 Writes deliberately disabled in demo mode.

Messages must never reveal keys, expected signatures, or sensitive content.

PreviousTroubleshooting

On this page

EndpointsIngest authenticationHeartbeatEventsSuite runsFleetOperational probesLoginErrors