---
title: "Submit a signed chain checkpoint to the witness"
method: POST
path: "/v1/witness/checkpoints"
tags: ["Audit"]
---

# Submit a signed chain checkpoint to the witness

`POST /v1/witness/checkpoints`

## Request

- Base URL: `https://api.headlessoracle.com`
- URL: `https://api.headlessoracle.com/v1/witness/checkpoints`
- Auth: one of:
  - none
  - HTTP bearer

Records an Ed25519-signed chain checkpoint and returns a receipt signed by Headless Oracle stating when it was received. The receipt attests only that at received_at the witness was shown a checkpoint validly signed by the key with that thumbprint; it does not attest who controls the key or that the records are true. Checks run in order and fail closed with 400 on the first failure: bad_request, bad_checkpoint_shape, bad_checkpoint_field, bad_jwk, kid_mismatch, bad_signature. checkpoint.sig is base64url without padding (86 chars), never hex. A checkpoint's identity is (kid, session_id, count, last_entry_hash): a new identity returns 201, a stored one returns 200 with the stored receipt. About 60 requests per minute per client address, counted per Cloudflare location; 2,000 new anonymous rows per UTC day, best effort. Optional Authorization: Bearer <Evidence plan key> counts against the key's own quota instead (up to 1,000 or 3,000 new checkpoints per UTC day) and is limited at about 600 per minute per address and per account. Full contract and honest limits: GET /v1/witness/spec.

## Request body

- object
  - `checkpoint` object, required
    - `v` 'evidence.action/1', required
    - `type` 'checkpoint', required
    - `session_id` string, required
    - `count` integer, required
    - `last_entry_hash` string, required
    - `ts` string, required
    - `kid` string, required: RFC 7638 thumbprint of public_key_jwk.
    - `sig` string, required: Ed25519 over the JCS bytes of the checkpoint without sig, base64url without padding.
  - `public_key_jwk` object, required
    - `kty` 'OKP', required
    - `crv` 'Ed25519', required
    - `x` string, required

## Response `200`

Identity already stored; the stored witness receipt

- WitnessReceipt: Signed by Headless Oracle. Every value is a string. Signing rule: all fields except signature, keys sorted, JSON.stringify with no whitespace, UTF-8, Ed25519, hex. Verify against the /v5/keys entry whose key_id equals public_key_id.
  - `type` 'witness.checkpoint/1', required
  - `witness` 'headlessoracle.com', required
  - `received_at` string, date-time, required
  - `kid` string, required
  - `session_id` string, required
  - `count` string, required: Decimal string.
  - `last_entry_hash` string, required
  - `checkpoint_ts` string, required
  - `checkpoint_sha256` string, required: sha256:<hex> over the JCS bytes of the full signed checkpoint, sig included.
  - `fork` 'true' | 'false', required: Best effort at issue time; detect forks by comparing receipts.
  - `public_key_id` string, required
  - `signature` string, required: Lowercase hex, 128 chars.

## Other responses

- `201`: Checkpoint stored; the new witness receipt
- `400`: A check failed; error is bad_request, bad_checkpoint_shape, bad_checkpoint_field, bad_jwk, kid_mismatch or bad_signature
- `401`: invalid_key: the Authorization header is malformed or names no key
- `402`: payment_required: the key is not active
- `403`: witness_plan_required: the key is not an Evidence plan key
- `429`: RATE_LIMITED, or quota_exceeded for an account over its daily quota; see Retry-After
- `503`: witness_unavailable: the store or key store is unavailable, or the anonymous daily cap is reached; no receipt is returned

---

[API](https://skmtc.dev/headlessoracle/apis/headless-oracle.md) · [All operations](https://skmtc.dev/headlessoracle/apis/headless-oracle/llms.txt) · [OpenAPI document](https://skmtc.dev/headlessoracle/apis/headless-oracle/revisions/4e82fe332f29?raw)
