Docs

HTTP API

Authenticate with a bearer credential and control the fleet with HTTP and WebSocket.

The hub serves one HTTP API, on port 7080 by default. The iOS app, the web cockpit and your orchestrator use it. The API uses JSON, and WebSocket for live streams.

Use the API on your private network only. The listener does not provide TLS. Read Security and privacy.

Authentication

Send a bearer credential on each request:

curl -fsS \
  -H "Authorization: Bearer $DROVER_BEARER" \
  http://127.0.0.1:7080/harness/hosts

A request without a valid credential returns 401. The health checks, the login page, pairing-code redemption and the host join probe need no credential.

Credential types

Credential Source Access
Device A pairing code from drover-server pair The fleet API. The phone holds one.
Host A pairing code from drover-server pair-host Host registration and relay.
Profile drover profile agents issue AGENT Read-only. Only the profile.
Preflight drover-server credentials issue-preflight Read-only. Health, release identity and the host list.
Shared token ~/.drover/api_token All routes, and operator actions.

The hub stores only a hash of each credential. To revoke one credential:

drover-server credentials list
drover-server credentials revoke <credential-id>

The shared token is on by default so that upgrades continue to work. After each device and host has its own credential, disable it:

# ~/.drover/config.toml
[auth]
legacy_token_enabled = false

For a script or an orchestrator, use a dedicated credential. A device or host credential gives shell access to each registered host.

Pair a client with the API

  1. Create a pairing code with an authenticated request:

    curl -fsS -X POST -H "Authorization: Bearer $DROVER_BEARER" \
      -H 'Content-Type: application/json' \
      http://127.0.0.1:7080/auth/pair-codes -d '{"scope": "device"}'
  2. Redeem the code on the new client:

    curl -fsS -X POST -H 'Content-Type: application/json' \
      http://127.0.0.1:7080/auth/pair \
      -d '{"code": "XXXX-XXXX", "device_name": "my-orchestrator"}'

A code is single use. A device code expires after ten minutes. A host code expires after fifteen minutes.

Endpoints

{id} is a session id. {host_id} is a host id. This list is not complete, and no OpenAPI schema exists.

Health

Method Path Purpose
GET /healthz Liveness. No credential.
GET /readyz Readiness. Detail needs a credential.

Fleet and hosts

Method Path Purpose
GET /harness Hosts and their sessions.
GET /harness/hosts Hosts, with connection type and available harnesses.
GET /harness/hosts/{host_id}/model-catalog Models that the host reports.
POST /harness/hosts/{host_id}/sessions Start a session.

Sessions

Method Path Purpose
GET /harness/sessions List sessions.
GET /harness/sessions/{id} Get one session.
GET /harness/sessions/{id}/messages Get the transcript, in pages.
POST /harness/sessions/{id}/turns Send a turn.
POST /harness/sessions/{id}/permission Answer an approval request.
POST /harness/sessions/{id}/interrupt Interrupt the current turn.
POST /harness/sessions/{id}/continue Hand off to another host or harness.
POST /harness/sessions/{id}/terminate Stop the session.
GET POST /harness/sessions/{id}/publications Read or record the branch and pull request of a session.
WebSocket /harness/sessions/{id}/stream Live structured events.
WebSocket /harness/sessions/{id}/terminal Live terminal.

Memory and analytics

Method Path Purpose
GET /profile The portable profile.
GET /sessions/history Past sessions.
GET /cockpit/overview Data for the cockpit home view.
GET /projects/activity Activity for each project.
GET /harness/lifecycle A report of idle sessions and worktrees.

Run a session

  1. Start a session. Set mode to structured for chat control, or to pty for a terminal:

    curl -fsS -X POST -H "Authorization: Bearer $DROVER_BEARER" \
      -H 'Content-Type: application/json' \
      http://127.0.0.1:7080/harness/hosts/studio/sessions \
      -d '{
        "mode": "structured",
        "harness": "codex",
        "cwd": "/path/to/project",
        "prompt": "Add rate limiting to the export endpoint."
      }'

    model and thinking_effort are optional. Take their values from the model catalog of the host.

  2. Send a turn:

    curl -fsS -X POST -H "Authorization: Bearer $DROVER_BEARER" \
      -H 'Content-Type: application/json' \
      http://127.0.0.1:7080/harness/sessions/SESSION_ID/turns \
      -d '{"text": "Also cover the empty config case."}'
  3. Answer an approval. Use the request id from the event stream. Set decision to allow or deny:

    curl -fsS -X POST -H "Authorization: Bearer $DROVER_BEARER" \
      -H 'Content-Type: application/json' \
      http://127.0.0.1:7080/harness/sessions/SESSION_ID/permission \
      -d '{"request_id": "REQUEST_ID", "decision": "allow"}'

    Only Claude Code sessions support approvals.

  4. Hand off the session to another host or harness:

    curl -fsS -X POST -H "Authorization: Bearer $DROVER_BEARER" \
      -H 'Content-Type: application/json' \
      http://127.0.0.1:7080/harness/sessions/SESSION_ID/continue \
      -d '{"target_host_id": "laptop", "target_harness": "claude-code"}'

    The two fields default to the values of the source session. The new session starts in the same directory path, so the project must be at that path on the target host.

Stop a session

POST /harness/sessions/{id}/terminate records your stop request, then contacts the host.

  • If the host confirms, the response is the normal success response.
  • If the host is offline or does not confirm, the response is 202 with "state": "pending".

A 202 means that the hub accepted the request. It does not mean that the process stopped. The hub confirms or tries again when the host connects.

Errors

Status Meaning
400 The input is not valid, or the harness cannot do the operation.
401 The credential is missing or not valid.
403 The scope of the credential does not permit this route.
503 An analytical route is busy or unavailable. Wait for Retry-After, then try again.

Analytical reads have a five-second deadline. They return an unavailable response, not partial data.

This page is a summary. The reference is docs/security.md.