Skip to main content
GET
Read one policy

Authorizations

Authorization
string
header
required

An Earnie API key, sent as Authorization: Bearer sk_earnie_.... Create one under Settings > API keys. The key's scopes decide which operations it may call.

Path Parameters

id
integer<int64>
required

Query Parameters

project_id
string<uuid>

Read the policy through this project's attachment. The project must belong to the caller's organization; a policy that exists but is not attached to it answers 404, because it is not this project's policy to show.

Response

The policy

id
integer<int64>
required
read-only
slug
string
required

Stable, human-readable identifier safe across deploys and migrations. Generated from name (kebab-cased) on Create when not supplied; templates ship with deterministic slugs (e.g. block-copyleft-licenses). Immutable after creation.

source
enum<string>
required

Server-managed origin of the policy. Seeded templates return seed; user-authored rows return custom.

Available options:
seed,
custom
module
string
required

Finding domain the policy targets (e.g. scans, crypto, crypto_finder). AI provenance is an xBOM enrichment, not a separate policy domain.

category
string
required

Grouping within a scanner (e.g. licenses, vulnerabilities).

name
string
required
description
string
required

Human-readable explanation of what the policy checks and why.

agent_rule
string
required

Keep it to roughly 200 bytes. That is not a stored-length limit — nothing rejects a longer one — it is where the RENDERED sentence is truncated with an ellipsis before it reaches an agent, measured after placeholders are substituted and in bytes rather than characters. A short rule whose {banned_licenses} expands to three hundred bytes is truncated too. The cap exists because this text sits in every prompt of every session.

Written in the second person, one sentence, no CEL: "Do not add dependencies licensed {banned_licenses}."

{key} placeholders name parameter_spec[].key entries and are substituted with the policy's current values at render time, so one sentence stays true after a parameter is tuned. A list value renders as a, b or c. A placeholder naming no parameter is rejected on save.

Empty is allowed and means "no agent rule": rendering falls back to description, and last to the CEL expression labelled as such, so a policy without one still reaches an agent. Like description it is prose and NOT part of the policy revision — rewording what an agent reads does not change what the gate does.

agent_rule_stale
boolean
required
read-only

True when agent_rule was written against different rule logic than this policy now carries — its action, expression, or the set of parameter keys has changed since the sentence was last saved.

An agent rule is hand-written prose and cannot be derived from CEL, so nothing keeps it true when the expression moves underneath it. This is how the product notices: the sentence still renders (it is usually still mostly right), but the policy is flagged so a human can review it. Saving the agent rule again clears the flag.

Parameter VALUES are deliberately excluded: {key} placeholders already keep the sentence true across a retune, so a threshold tweak never raises this. False when the policy has no agent rule, and false for a row that predates the stored basis — "unknown" must not read as "stale".

enabled
boolean
required
action
enum<string>
required

Enforcement action applied when the policy fires. Verdict mapping: block → block warn → warn require → require

Available options:
block,
warn,
require
expression
string
required

CEL string. Compiled via cel-go on save (parse + type check + params.X consistency) and evaluated against findings via Eval (see /preview for the live-evaluation surface).

parameter_spec
object[]
required
values
object
required

Current parameter values keyed by parameter_spec[].key. Every declared key needs a value or a default in its spec entry, including a parameter the expression only reads behind has(); a key left out is stored with its default. See ValuesInvalidError.

revision
string
required
read-only

The policy's immutable content revision: a sha256: digest over the canonical form of the gating content — action, expression, parameter_spec, values. It is byte-identical to the policy_hash an evaluation records and to the revision a scan's policy snapshot names, so "which revision produced this verdict" and "which revision is live now" are answered in one vocabulary.

Mutations echo it back in If-Match. A stale revision is 409 policy_conflict; a policy edit is never last-write-wins.

It covers the gating content and nothing else. Renaming a policy or rewriting its description leaves the revision unchanged, because neither changes what the gate does, and enabled is carried by presence in a scan's snapshot rather than by the digest.

created_at
string<date-time>
required
read-only
updated_at
string<date-time>
required
read-only
result_summary
object