---
title: "Approve or reject one fact"
method: PATCH
path: "/briefs/{id}/facts/{factId}"
tags: ["Briefs"]
---

# Approve or reject one fact

`PATCH /briefs/{id}/facts/{factId}`

## Request

- Base URL: `https://next.frase.io/api/v1`
- URL: `https://next.frase.io/api/v1/briefs/{id}/facts/{factId}`
- Auth: API key in header `X-API-KEY`

Approving a claim lets generation state it and require it through a rewrite; rejecting excludes it permanently — no later research run or replay can hand a rejected claim back. `expected_updated_at` is required and must be the exact `updated_at` you read for this fact; literal null is rejected, because a fact row is stamped at mint and can never have a null timestamp.

## Path parameters

- `id` string, uuid, required
- `factId` string, uuid, required

## Request body

- object
  - `approval` 'approved' | 'rejected', required
  - `expected_updated_at` string, date-time, required

## Response `200`

The updated fact, carrying its rotated `updated_at`

- object
  - `data` object
    - `fact` Fact: One claim in a brief's fact ledger. Colour in the UI is provenance x verification; the API returns both so a client can reproduce it.
      - `id` string, uuid
      - `claim` string
      - `figure` object, nullable: The typed number the claim states, when it states one.
        - `value` number
        - `unit` string
        - `asOf` string
      - `provenance` 'research_grounded' | 'research_asserted' | 'customer' | 'imported' | 'generated'
      - `sources` FactSource[]
        - `url` string, uri: Absent when the source was named but not linked.
        - `decision_url` string, uri: The durable source-decision key. Usually identical to `url`; after a replacement it remains the original URL. Send this value as `source_url` when changing the decision again.
        - `title` string: Publisher or page title.
        - `domain` string: Derived from `url`; absent whenever it is.
        - `tier` string: Authority tier from the citations classifier, when known.
        - `verbatimQuote` string: The excerpt from the source carrying the claim.
        - `retrievedAt` string, date-time
        - `state` 'ai_verified' | 'human_verified' | 'unverified' | 'needs_human_check' | 'discarded': What we know about the page behind `url`. `ai_verified` — we opened it and found the claim, and `verbatimQuote` is copied from it. `human_verified` — a person vouched for it, and re-running research will not change it. `unverified` — nothing established the claim either way; see `stateReason`. `needs_human_check` — the site refused our request, usually bot protection rather than a missing page. `discarded` — the page is gone, so the claim is kept and the link is not usable. Absent on sources minted before 2026-09-14.
        - `stateReason` string: Why `state` is what it is. The one value worth branching on is `unsupported`: the page was READ and the claim was NOT on it, which is a different situation from not having been checked — and the two are indistinguishable from `state` alone, because both are `unverified`. Other values describe the fetch (`http_gone`, `blocked`, `not_parsed`, `unreachable`, `reachable`) and are informational.
        - `finding` string: The checker's own sentence when it read the page and did not find the claim. Model-authored prose meant for a person to read, present only with `stateReason: "unsupported"`. Never parse it — branch on `stateReason` and show this.
      - `removed_sources` object[]: Decision receipts for sources removed from this claim. They are not citable sources; use their URL to address a later restoring decision.
        - `url` string, uri
        - `decided_at` string, date-time
      - `verification` 'verified' | 'undetermined' | 'unverified' | 'refuted' | 'customer_attested'
      - `approval` 'pending' | 'approved' | 'rejected': Minted facts default to `approved` — the flag is what lets a claim into generation, and a ledger that starts everything at `pending` is a queue nobody works. A rejection is permanent: re-minting the same claim never resets it. Claims the writer asserted in its own output (`provenance: generated`) are the one class held at `pending`.
      - `section_binding` string, nullable: Normalised heading this claim belongs to, when bound.
      - `updated_at` string, date-time: Echo this as `expected_updated_at` on the approval PATCH.

## Other responses

- `400`: Validation failed
- `401`: Authentication failed
- `403`: Forbidden - action not allowed on this resource
- `404`: Resource not found
- `409`: The fact changed since you read it. Re-read and retry with the current `updated_at`.

---

[API](https://skmtc.dev/frase/apis/frase-api.md) · [All operations](https://skmtc.dev/frase/apis/frase-api/llms.txt) · [OpenAPI document](https://skmtc.dev/frase/apis/frase-api/revisions/7fb75d89f7a4?raw)
