# GRRC Certification — Verification API Reference (v1)

**Status:** Implementer reference — Phase 34 / Slice 222 (`VERIFY-API-COMPLETE`). Authored FROM the built endpoints. Pairs with the **Independent Verification Specification** (the algorithm + formats) and the **Bounded-Claim Statement** (what verification asserts and does not).

**Base path:** `/api/v1/grrc/verify`. All routes key off the abstract role `grrc` + the robot UUID + a crypto-agile key-id — **no operator/company name** appears in any route, payload, or identifier (CD #864).

**Hosting note.** The endpoint is **convenience over the offline floor** (trust-model (iv-2)): it only restates what an independent offline verifier confirms from the published signed artifacts and anchor. It is never the only path and never a gate. The mirrorable resource endpoints (`/bundle`, `/anchors`, `/revocation`) let a relying party fetch the inputs and verify them themselves, on infrastructure they control. *(The production prod-deploy of this surface at the GRRC verification domain is a gated follow-on; the floor is domain-independent.)*

---

## Auth tiers

| Tier | Routes | Access |
|---|---|---|
| **Public** (unauthenticated, (iv-4)) | `/{robotUuid}`, `/{robotUuid}/bundle`, `/{robotUuid}/anchors`, `/{robotUuid}/revocation` | Anyone may confirm the cert claim and mirror the inputs. |
| **Authorized full-record** (owner / authorized auditor, (iv-3)/(iv-4)) | `/{robotUuid}/full`, `/{robotUuid}/full/record` | `developer_mode` policy. Carries the sequence horizon and the chain segment. |

When no verification bundle is provisioned for the robot, every route fails **safe** with `404` `application/problem+json` (never `500`; the public routes are anonymous, so the 404 — not a 401 — proves the tier is genuinely open).

---

## Public endpoints

### `GET /api/v1/grrc/verify/{robotUuid}`
Confirms the robot's public GRRC certification claim. **(iv-3):** carries **no** sequence horizon (a boolean `ChainIntegrityConfirmed` only — no enumerable timeline; honors `S219-CARRY-CHECKPOINT-SEQUENCE-EXPOSURE`).

`200` body:
```
{
  "robotUuid": "<guid>",
  "certStatus": "valid | expired | revoked | self-de-certified | superseded | genuineness-failed | integrity-broken | indeterminate",
  "genuinenessConfirmed": <bool>,
  "genuinenessKeyId": "<certifier key-id | null>",
  "chainIntegrityConfirmed": <bool>,
  "overallVerified": <bool>,
  "asOfUtc": "<ISO-8601>",
  "doesNotAssert": "<owner-authored (iv-1) explicit negative, verbatim>"
}
```

### `GET /api/v1/grrc/verify/{robotUuid}/bundle`
The mirrorable **verification bundle** — the offline-verifiable artifact JSON (the certifier-signed grant + cert-status checkpoint + signed anchor/revocation statement). Public tier: **no chain segment**. `Content-Type: application/vnd.grrc.verification-bundle.v1+json`. Fetch it, re-host it on any mirror, and verify it offline against the published anchor.

### `GET /api/v1/grrc/verify/{robotUuid}/anchors`
The published **trusted-anchor set** backing this robot's certification (`{ FormatVersion, Anchors: [{ KeyId, Algorithm, PublicKeySpkiBase64 }] }`). `Content-Type: application/vnd.grrc.trust-anchor-set.v1+json`. The public key bytes a relying party verifies the bundle against.

### `GET /api/v1/grrc/verify/{robotUuid}/revocation`
The signed, mirrorable **revocation / anchor-currency statement** (`{ FormatVersion, AnchorStatementPayloadBase64 }`). `Content-Type: application/vnd.grrc.revocation-statement.v1+json`. A clearance is current iff its key-id appears in the statement's signed `trustedKeyIds`; the statement timestamp makes staleness visible. Fetch the freshest copy from any mirror.

---

## Authorized full-record endpoints (`developer_mode`)

### `GET /api/v1/grrc/verify/{robotUuid}/full`
The authorized verification result: the public bounded result **plus** the sequence horizon and head hash the (iv-3) boundary keeps off the public tier. When a full-record artifact is provisioned, `chainWalkPerformed` is `true` and the result reflects the **full independent chain-integrity walk** (not the certifier checkpoint alone) — closing the offline-floor's thin-walk residual.

`200` body:
```
{
  "robotUuid": "<guid>", "certStatus": "<token>",
  "genuinenessConfirmed": <bool>, "genuinenessKeyId": "<key-id|null>",
  "chainIntegrityConfirmed": <bool>,
  "intactThroughSequence": <int64|null>, "headChainHashBase64": "<base64|null>",
  "revocationCurrent": <bool>, "overallVerified": <bool>,
  "asOfUtc": "<ISO-8601>", "doesNotAssert": "<(iv-1) verbatim>",
  "chainWalkPerformed": <bool>,
  "diagnostics": [ "<string>", ... ]
}
```

### `GET /api/v1/grrc/verify/{robotUuid}/full/record`
The authorized **full-record artifact** — the offline-verifiable artifact carrying the robot's **chain segment** + the **published robot audit public key**, so the auditor runs the **full independent two-leg verification offline**. `Content-Type: application/vnd.grrc.full-record.v1+json`.

**verify ≠ decrypt:** the chain segment carries the encrypted envelope (ciphertext) only — never plaintext. It is erasure-compatible by construction. **(iv-3):** the segment (the event sequence) is served **only** on this authenticated tier.

---

## Verifying offline (the floor, the architecturally honest path)

The endpoint is a courier; the durable guarantee is offline verification. Reference flow:

1. Fetch `/bundle` (+ `/anchors`, `/revocation`) — or, for the full walk, the authorized `/full/record`.
2. **Cut the network.** From here, only the saved files + a verifier are used.
3. Run the offline verifier (the shipped `Res.Tools.GrrcVerify`, or your own per the Independent Verification Specification):
   ```
   Res.Tools.GrrcVerify --artifact <bundle-or-full-record>.json --anchor-pem <anchor>.pem --anchor-key-id <key-id> [--as-of <iso-8601>]
   ```
   Exit codes: `0` valid · `3` a bounded non-valid status (expired / revoked / superseded / self-de-certified / genuineness-failed / integrity-broken) · `1` indeterminate / usage error.

The offline result is byte-identical to the public endpoint on the bounded fields. That equivalence — endpoint and offline floor agreeing, with the endpoint switched off — is the proof that the hosted path is convenience, never a gate.

---

## Stable, versioned formats

Each resource carries a `FormatVersion` (or `schemaVersion`); a consumer **must reject** a version it does not understand rather than best-effort parse it. Versions bump only on a breaking wire change; additive optional fields keep the version. A GRRC clearance lives ~1 year — verify against this contract for that lifetime.

---

*End of the GRRC Verification API Reference (v1) — Phase 34 / Slice 222. The implementer doc tier (this reference + the spec + the bounded-claim statement) is authored FROM the built resources so it cannot drift from what shipped. The end-user / demo-application packaging of these is a separate follow-on slice.*
