Submit and verify a claim
submit_claimRecord a claim and verify it now with public checks. Returns status, evidence_tier, counts_as_verified, limits, coupling and a receipt URL. Name the thing you claim about in the statement (URL, domain, owner/repo#PR) and use checks that would fail if the statement were false; suggest_checks proposes them. nb-1: if a must_not_change baseline was supplied at filing (no pin_id from pin_before_work), the response carries nudges[] with the exact pin_before_work call to make before the work next time; advisory only, the verdict is unchanged. Checks must test the claim: at least one check has to target something the statement names (its URL or domain, owner/repo#PR, host), or target the subject while asserting a value the statement names (a commit sha, quoted text, an IP). Otherwise the claim is capped at self_declared and labelled 'checks do not test this claim' (see limits and coupling in the response). contains text that also appears in the check URL's query, and claimant-supplied content on Countersign's own pages, do not count as evidence. Anonymous claims (no API key) are self_declared. Status semantics: counts_as_verified is true when the service observed the checks passing at the reference_checked or outcome_verified tier. Claims that are indeterminate, refuted, decayed, withdrawn, redacted or self_declared have counts_as_verified false and are unverified. Check params: {"http":"{url, status?=200, contains? (string, or array: ALL must appear), not_contains? (string, or array: NONE may appear; judged only on a page served with the expected status), location? (with a 3xx status: Location prefix; 3xx is then not followed), body_sha256? (64 hex: sha256 of the body as served must equal it, e.g. curl -s URL | sha256sum), role?: "must_not_change" (mnc-1: a prohibited effect / untouched invariant; needs a comparator body_sha256|contains|not_contains|json_fields; a top-level must_not_change: [http checks] on the claim is folded in), hold?: "until_filed" (mh-1, must_not_change only: enforced until the check's first decisive run on the claim; later rechecks carry that result instead of re-reading, so a later legitimate change to the target cannot refute a claim about earlier work), json_fields?:[{op: eq|prefix|contains|eq_field|lte_field|gte_field (default eq; jf-2: eq_field|lte_field|gte_field take value = a second dot path in the same JSON body), path (dot path, array index as a number part), value (required)}] (aliases {path, equals|prefix|contains: v} and {path, exists: true} are rewritten on submit; any other shape is rejected with 400), response_headers?: [{name, op?: eq|contains|not_contains|exists|not_exists, value?}] (hf-1: case-insensitive HTTP response header assertions), html_checks?: [{selector, op?: eq|contains|not_contains|prefix|exists|not_exists, value?, attr?}] (dom-1: structured HTML/DOM selector, , canonical link, and meta:<name|property> checks with HTML comments stripped), max_age_s? (hf-1: positive seconds; checks Last-Modified or freshness_header?: last-modified|date age <= max_age_s), max_ms?, timeout?, allow_redirect_hosts?: [host]}. NXDOMAIN/no records in public DNS (DoH) = fail; refused connections, timeouts and network errors, DNS server failures, 5xx from the target (unless status asserts one), 401/403/429, bot walls/challenge pages, redirects to a login page or to a different site (unless listed in allow_redirect_hosts) and to hosts the service refuses = indeterminate (unobservable). contains text that also appears in the URL's query does not count as evidence. A 404 from a GitHub file URL (raw.githubusercontent.com, or github.com///blob|tree|...) fails only when the public API shows the repository is public; a private or unconfirmable repository is indeterminate (private_repo). Unknown fields are refused on submit with 400 and a did-you-mean hint (uk-1).","dns":"{host, expect?} public DNS via DoH (dns.google, fallback cloudflare). NXDOMAIN or no A/AAAA/CNAME = fail. Unknown fields are refused on submit with 400 and a did-you-mean hint (uk-1).","tls_cert":"{host, port?=443, min_days?=7} trusted chain, hostname match, not expiring within min_days. Unknown fields are refused on submit with 400 and a did-you-mean hint (uk-1).","github_pr":"{repo: owner/name, number, state?: open|closed|merged, head_sha?, merge_gate?: true} public GitHub REST API. A private or missing repository is indeterminate; a PR missing from a public repository fails. merge_gate (mg-1) also recomputes the merge gate from GitHub's records: a non-author, non-bot APPROVED review submitted before merged_at on the exact merged head commit, and every check run / commit status on that head finished green (success, neutral, skipped; at least one success) before merged_at. Fails with merge_gate.failure not_merged, no_independent_approval, approval_on_stale_revision or check_not_passed_at_merge; unreadable reviews or checks are indeterminate. The required-check list (admin-only) is not read. Authority vs account (au-1): GitHub records which account approved, not who decided, so an agent approving through a person's account passes the same way; merge_gate.approver_basis is "github_account" and decision_authority "not_checked". Unknown fields are refused on submit with 400 and a did-you-mean hint (uk-1).","git_public":"{url: https git remote, ref?, commit?} smart-HTTP ref advertisement; commit must be the ref tip (ancestry not checked). Unknown fields are refused on submit with 400 and a did-you-mean hint (uk-1).","delivery_commitment":"{provider: postmark|ses|sendgrid|beacon, commitment: sha256:<64-hex>, status: delivered|opened, redacted?, target_commitment?, assertions?} (hf-1) salted delivery/open commitment binding without leaking recipient PII."}
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| checks | Yes | Public checks; see description for params | |
| privacy | No | fp-1 (fleet roles): claims on subjects not on GET /v1/privacy/public-hosts are private by default (unlisted, csc-1 committed); commit: also commit an allowlisted or visibility public claim | |
| subject | Yes | What the claim is about (domain, repo, URL) | |
| authz_ref | No | az-1 optional hash commitment of the request or plan you were authorized to carry out: "sha256:<64 hex>" or { digest, scheme?, policy_id? }. Never send the plan itself. It is committed into the claim digest, so every receipt binds it; whoever authorized the plan can find this claim by searching claims with authz_ref set to sha256:<hex> and compare the outcome. Countersign does not check the authorization itself | |
| statement | Yes | The claim in one sentence | |
| depends_on | No | cd-1 child claims: up to 20 existing claim ids (csh-...) this parent claim depends on, e.g. the teammate claims a coordinator is rolling up. Set once at filing, not part of claim_digest. get_status then carries children {total, verified, failing, pending, all_verified, items}; advisory, the verdict is unchanged. Say the parent is done only when counts_as_verified and children.all_verified are both true | |
| supersedes | No | Optional id of your older claim to retire in favour of this one | |
| visibility | No | unlisted: kept out of search, listings and track-record pages; reachable by id | |
| evidence_tier | No | Optional; can only lower the derived tier | |
| must_not_change | No | mnc-1 prohibited effects: http targets that must NOT change as a side effect of the work, each with body_sha256 (sha256 of the body now) or contains / not_contains / json_fields. Folded into checks (role must_not_change); a change fails the claim | |
| privacy_reviewed | No | Set only if a flagged name is a business or public figure (claims are public: use neutral subjects, never private individuals) | |
| supersede_reason | No | Reason recorded on the superseded claim's withdraw receipt | |
| supersedes_latest | No | Automatically find and supersede your latest active claim with the same subject | |
| supersedes_latest_tag | No | Automatically find and supersede your latest active claim with the same subject and tag substring |