API Reference / v1

GET /api/v1/metrics/{id}/contract

The agent-facing trust-contract envelope. This is what an AI agent sees when it asks ClariLayer for the canonical context of a metric: the business definition, the currently-approved version, the live discourse signal, and the admin-curated notes a human pinned for the agent to read.

A typical CTO/CAIO evaluation pipes this response into a system prompt before the agent answers a question that references the metric. The envelope is designed so the agent can ground its answer without making a second call.

Request

GET https://app.clarilayer.com/api/v1/metrics/{id}/contract
Authorization: Bearer <api_key>
Accept: application/json

The API key must carry thecanonical-metric-api:readscope. The route resolves the metric inside the API key’s org; cross-org access returns404(existence is cloaked).

Response (200 OK)

Default response. Every field shown is always present unless documented otherwise; counts default to0and arrays default to[]so consumers can read inner fields without outer null-checks.

{
  "data": {
    "metric_id": "5e6f7a1b-2c3d-4e5f-8a9b-0c1d2e3f4a5b",
    "name": "Active Customer Count",
    "business_definition": {
      "included": "Customers with at least one billable subscription in the trailing 30 days.",
      "excluded": "Internal test orgs (org_type='internal'), churned accounts whose cancellation date is on or before the period start.",
      "time_window": "trailing 30 days, anchored on the most recent UTC midnight",
      "caveats": "Free-tier customers count as active. Self-serve and sales-led accounts are aggregated together.",
      "legacy_description": "Number of customers we consider active."
    },
    "current_approved_version": {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "definition_version": "2.1.0",
      "released_at": "2026-04-22T14:08:11.000Z"
    },
    "last_validated_at": "2026-05-09T09:14:00.000Z",
    "lifecycle_status": "RELEASED",
    "challenges_count": 4,
    "open_challenges_count": 1,
    "requires_disambiguation": null,
    "canonical_url": "https://app.clarilayer.com/metrics/5e6f7a1b-2c3d-4e5f-8a9b-0c1d2e3f4a5b",
    "discussion_thread_count": 3,
    "discussion_message_count": 11,
    "agent_context_notes": [
      {
        "message_id": "11111111-2222-4333-8444-555555555555",
        "thread_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
        "intent": "decision_rationale",
        "author_display_name": "Jamie Chen",
        "body": "Exclude org_type='internal' from the active count. Decided in the 2026-Q1 metrics review after a test workspace skewed the board chart.",
        "pinned_at": "2026-04-23T16:42:00.000Z",
        "created_at": "2026-04-23T16:30:00.000Z"
      },
      {
        "message_id": "22222222-3333-4444-8555-666666666666",
        "thread_id": "bbbbbbbb-cccc-4ddd-8eee-ffffffffffff",
        "intent": "clarification",
        "author_display_name": "Priya Patel",
        "body": "Trailing 30d anchors on UTC midnight — not the org's fiscal calendar. Confirmed with Finance for the May board pack.",
        "pinned_at": "2026-05-02T11:05:00.000Z",
        "created_at": "2026-05-02T10:48:00.000Z"
      },
      {
        "message_id": "33333333-4444-4555-8666-777777777777",
        "thread_id": "cccccccc-dddd-4eee-8fff-aaaaaaaaaaaa",
        "intent": "objection",
        "author_display_name": "Marcus Rivera",
        "body": "Free-tier should be reported separately for ARR conversations. Tracked in metric_challenges#open — see open_challenges_count.",
        "pinned_at": "2026-05-08T19:21:00.000Z",
        "created_at": "2026-05-08T19:12:00.000Z"
      }
    ],
    "discourse_summary": {
      "open_objections_count": 1,
      "open_proposals_count": 0,
      "last_activity_at": "2026-05-09T08:02:00.000Z"
    }
  },
  "meta": { "apiVersion": "v1" }
}

New envelope fields (v1)

The metric-contract envelope was extended with six fields that surface the Reasoning Trail half of the corpus. Legacy v1 consumers can ignore them; agents that consume them get a richer grounding signal.

discussion_thread_count
number
Total threads on this metric across every intent and resolution status. The 'is there any conversation at all' signal. Defaults to 0.
discussion_message_count
number
Total non-deleted messages across all threads on the metric. Soft-deleted rows are excluded so the count aligns with what a human sees in the Notes tab. Defaults to 0.
agent_context_notes[]
AgentContextNote[]
Admin-pinned notes curated for AI context, ordered by pin time (most recent first) and capped at 10 by the route. Each entry carries message_id, thread_id, intent, author_display_name, body, pinned_at, and created_at. Empty array when no notes are pinned.
discourse_summary
DiscourseSummary | null
By-intent live-dispute signal: open_objections_count, open_proposals_count, last_activity_at. NULL when no thread on the metric carries intent='objection' or intent='proposal' (regardless of resolution).
discussion_summary
string | null (optional)
Plain-text LLM summary of the discussion. Only present when the caller passes ?summary=true. Omitted (not null) on the default response.
discussion_summary_meta
{ cache_hit: boolean; charged: boolean } (optional)
Caching and billing metadata for the LLM summary. cache_hit is true when a previously-generated summary served the call. charged is true exactly when a new billable meter event was persisted. Omitted on the default response.

Consumer semantics

Treat the contract as the metric’s current approved context, not as a warehouse execution endpoint. The response tells a consumer which business definition, approval state, latest released version, validation timestamp, and curated discussion notes should travel with an answer. Query execution, BI rendering, and warehouse permissions remain owned by the systems that consume the contract.

Thelifecycle_statusfield is the fastest trust signal. A released or approved metric can be used in production workflows according to your workspace policy. A candidate or draft metric should be handled as advisory context unless the consuming workflow explicitly accepts pre-release definitions. Deprecated metrics remain readable so downstream systems can show migration guidance instead of silently dropping context.

Freshness is exposed through multiple fields because different consumers need different checks. Usecurrent_approved_version.released_atto understand when the approved definition last changed,last_validated_atto understand when the latest validation evidence ran, anddiscourse_summary.last_activity_atto understand whether the human conversation has moved since the agent last cached context.

Error and access model

Authentication happens before any metric lookup. Missing, malformed, or revoked API keys return an auth error; keys that do not includecanonical-metric-api:readare rejected before the route reads contract data. Invalid metric IDs return400because the route can determine the ID shape without revealing whether a metric exists.

Cross-organization access is cloaked as404after authentication. That means a consumer should not use the difference between “not found” and “not in this org” as a discovery channel. If a workflow expects a metric to exist but receives404, the safest operator action is to verify the API key’s workspace and the metric ID source together.

Discussion counts and agent-context notes degrade conservatively if a supporting read fails: counts fall back to0, arrays fall back to[], and optional summaries can returnnullwith an explanatory header. Consumers should surface those degraded states as missing context, not as proof that no human discussion exists.

Pin safety limit

Theagent_context_notes[]array is bounded upstream by the shared per-metric pin safety limit and capped on the response at 10 entries to protect agent token budget.

See full pricing table

?summary=true (opt-in)

Append?summary=trueto request a natural-language LLM summary of the metric’s discussion. When the request lands on a previously-cached input hash, ClariLayer returns the cached summary (cache_hit: true); cache misses generate a fresh summary.

Cache misses are a metered overage on billable plans (Starter, Team, Enterprise, Design Partner). The Developer plan serves cache hits and runs the generator on cache misses but is not billed; this is intentional so a personal workspace can light up the demo without a credit card.

GET https://app.clarilayer.com/api/v1/metrics/{id}/contract?summary=true
Authorization: Bearer <api_key>

// Response (200 OK) — abbreviated, only the appended fields shown:
{
  "data": {
    ...
    "discourse_summary": {
      "open_objections_count": 1,
      "open_proposals_count": 0,
      "last_activity_at": "2026-05-09T08:02:00.000Z"
    },
    "discussion_summary": "Active Customer Count is defined as customers with a billable subscription in the trailing 30 days, anchored on UTC midnight. Internal test orgs are excluded by team decision in 2026-Q1. One open objection (Marcus Rivera) argues free-tier customers should be reported separately for ARR conversations; this is tracked as an open metric challenge and has not yet been resolved.",
    "discussion_summary_meta": {
      "cache_hit": false,
      "charged": true
    }
  },
  "meta": { "apiVersion": "v1" }
}

The response also carries anX-Discussion-Summary-Chargedheader (0/1) so downstream meters can read the billing decision without parsing the body. Degraded responses (LLM timeout, daily-cap exceeded, pricing-state unavailable) returndiscussion_summary: nullwith an explanatoryX-Discussion-Summaryheader.

See also