Autonomous AgentsREST & CLIView as /llms.txt

Agent Integration Guide

Complete guide for AI agents to discover counters, build and maintain dashboard boards, mint scoped credentials, and self-destruct keys.

1. Discover

Query data plane counters via GET /v1/counters.

2. Build Boards

Compose stat tiles, charts, and tables up to 12 widgets per board.

3. Mint Keys

Delegate narrow, temporary keys for worker sub-agents via key:mint.

4. Self-Destruct

Revoke credentials on completion with DELETE /v1/keys/self.

1. The Two Hosts and Authentication

counters.dev operates two separate hosts with distinct responsibilities. Every request carries the exact same authorization header:

Request Header
Authorization: Bearer sk_live_...
HostSurfaceEndpointsAccepted Credential
https://api.counters.devData PlaneGET /v1/counters, values, seriesOrganization API key (sk_live_...)
https://hub.counters.devHub & Control Plane/v1/boards*, /v1/keys*Organization API key (sk_live_...)

2. Scopes Matrix

API keys possess granular permissions. The board and key endpoints strictly check required scopes on every call:

OperationHostEndpointRequired Scope
List & discover countersapi.counters.devGET /v1/counterscounter:read
List or get boardshub.counters.devGET /v1/boards, GET /v1/boards/{boardId}board:read
Create or update boardshub.counters.devPOST /v1/boards, PUT /v1/boards/{boardId}board:write
Delete boardshub.counters.devDELETE /v1/boards/{boardId}board:manage
Mint child API keyshub.counters.devPOST /v1/keyskey:mint
Self-destruct calling keyhub.counters.devDELETE /v1/keys/selfNone (any key can self-revoke)

When a scope check fails, the API answers with 403 Forbidden and body:

Problem Detail (scope_denied)
{
  "type": "scope_denied",
  "required": "board:write"
}

3. Step 0: Discover Existing Counters

Widgets reference counters by string key. Always list existing counters first to confirm exact spellings. Format validation accepts any valid key (^[A-Za-z0-9._:-]+$, ≤ 200 chars), but a misspelled key will simply render an empty tile without raising an error.

List Counters (Data Plane)
curl -s "https://api.counters.dev/v1/counters?limit=100" \
  -H "Authorization: Bearer $COUNTERS_API_KEY"
Response Example
{
  "data": [
    { "key": "signups", "value": "12912", "epoch": 1 },
    { "key": "active_sessions", "value": "842", "epoch": 1 },
    { "key": "api_requests", "value": "450201", "epoch": 1 }
  ],
  "nextCursor": null
}

4. Boards & The Five Widget Types

A board document contains a name and an array of up to 12 widgets (total payload limit: 32 KiB). Server-minted fields (id, createdAt, updatedAt, revision) are generated by the server and must never be sent on write operations.

stat

Stat tile with a single large number

• Size: s (1 column)
• Options: { "format": "compact" | "exact" } (default "compact")

ticker

Compact live counter ticker

• Size: s (1 column)
• Options: { "format": "compact" | "exact" } (default "compact")

delta-chart

Delta line/bar chart over time intervals

• Size: l (full row) or m
• rangePreset: "24h", "7d", "30d", "90d", "12mo" (default "7d")
• bucket: "1m", "5m", "1h", "1d", "1w", "1mo"

goal

Goal progress against a human-supplied target

• Size: m (2 columns)
• options.target: string decimal (e.g. "1000000"). Ask human operator; never invent targets.

table

Table listing historical bucket values

• Size: m (2 columns)
• rangePreset, bucket, and limit (1–1000 rows).

5. Creating Boards (POST /v1/boards)

Always supply a lowercase UUID v4 in the Idempotency-Key header. This guarantees that network retries never produce duplicate boards.

Create Board Request
curl -X POST "https://hub.counters.dev/v1/boards" \
  -H "Authorization: Bearer $COUNTERS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 123e4567-e89b-12d3-a456-426614174000" \
  -d '{
    "name": "Production Metrics",
    "widgets": [
      {
        "id": "w1",
        "type": "stat",
        "counterKey": "signups",
        "title": "Total Signups",
        "size": "s",
        "options": { "format": "compact" }
      },
      {
        "id": "w2",
        "type": "delta-chart",
        "counterKey": "signups",
        "title": "Daily Signups",
        "size": "l",
        "options": { "rangePreset": "7d", "bucket": "1h" }
      }
    ]
  }'

On success (201 Created), record the returned id and revision: 1 for any future modifications.

6. Updating Boards & Optimistic Concurrency

Updates replace the board whole. Always supply the If-Match header with the exact stored integer revision.

Update Board Request
curl -X PUT "https://hub.counters.dev/v1/boards/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer $COUNTERS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "If-Match: 1" \
  -d '{
    "name": "Production Metrics (Refreshed)",
    "widgets": [ ...new complete array of widgets... ]
  }'

7. Deleting Boards (DELETE /v1/boards/{boardId})

Deleting a board requires board:manage. It deletes the layout only; counter data and history remain completely intact.

Delete Board Request
curl -X DELETE "https://hub.counters.dev/v1/boards/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer $COUNTERS_API_KEY"

8. Key Minting & Delegation Recipe

In multi-agent systems, avoid sharing root keys. Use the delegation pattern: an orchestrator holding key:mint mints a temporary, least-privilege key for a sub-agent. When the sub-agent finishes, it calls DELETE /v1/keys/self to self-destruct its key.

Step 1: Orchestrator Mints Scoped Child Key

Requires key:mint. Scopes must be a subset of caller's own scopes.

Step 1: Orchestrator Mints Scoped Child Key
curl -X POST "https://hub.counters.dev/v1/keys" \
  -H "Authorization: Bearer $COUNTERS_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "worker-board-builder",
    "scopes": ["counter:read", "board:read", "board:write"],
    "expires_at": "2026-09-27T12:00:00Z"
  }'

Step 2: Sub-Agent Executes & Self-Destructs

Any key can call this. Revocation is permanent (returns 401 afterwards).

Step 2: Sub-Agent Executes & Self-Destructs
curl -X DELETE "https://hub.counters.dev/v1/keys/self" \
  -H "Authorization: Bearer $SUB_AGENT_KEY"

9. Error Handling Reference

StatusProblem TypeMeaning & Recommended Action
400bad_requestMalformed body, unknown fields, missing If-Match, or malformed UUID. Fix payload against schema.
401unauthorizedMissing, expired, or revoked API key, or sent JWT instead of API key. Re-obtain valid key.
403scope_deniedKey lacks required scope. Check problem required member and ask human operator for that scope.
404not_foundUnknown boardId, cross-org resource, or organization board surface is disabled. If all board routes 404, notify operator that board gate is disabled.
409 / 412conflict / concurrencyStale If-Match revision or Idempotency-Key conflict. Re-fetch board via GET, merge, and retry.
413payload_too_largeBoard exceeds 32 KiB cap. Use fewer widgets (cap 12) or shorter titles.
429rate_limitedPer-key rate limit exceeded (20 rps). Wait according to Retry-After header and retry.

10. Operator & Agent Checklist

Obtained an organization key with counter:read, board:read, and board:write.
Queried data plane GET /v1/counters to verify exact counter keys before adding widgets.
Generated a fresh lowercase UUID v4 for Idempotency-Key on board creation.
Maintained board constraints: maximum 12 widgets and 32 KiB size limit.
Consulted the human operator for goal widget targets (never guessed or assumed).
Used If-Match for updates and properly handled 409/412 optimistic concurrency conflicts.
Revoked temporary or sub-agent keys with DELETE /v1/keys/self upon completion.