Sealed artifact endpoints
Six endpoints, one per outcome state, each returning the sealed artifact for a run in that state. The five receipts are checked offline with verdifax-verify; an allowed run is checked through its full record.
See Outcome states & sealed artifacts for the conceptual overview and field-level schema.
Endpoints
GET /runs/{id}/allow-token → AllowToken (PEPG admit + nine-stage pipeline)
GET /runs/{id}/deny-receipt → DenyReceipt (PEPG)
GET /runs/{id}/ccv-halt-receipt → CCVHaltReceipt (CCV)
GET /runs/{id}/macc-halt-receipt → MACCHaltReceipt (MACC)
GET /runs/{id}/aivp-t4-halt-receipt → AivpT4HaltReceipt (AIVP-T4)
GET /runs/{id}/attestation-gap-receipt → AttestationGapReceipt (admission)
Each endpoint returns the sealed artifact for run {id} if and only if the run resolved to the matching outcome state. Otherwise it returns 404 Not Found with a clear error explaining which state the run is in.
How to pick the right endpoint: Use the outcome_kind field from the run summaries (GET /runs or GET /runs/search); GET /runs/{id} carries the same value as status:
ok→/runs/{id}/allow-tokenpepg_deny→/runs/{id}/deny-receiptccv_halt→/runs/{id}/ccv-halt-receiptmacc_halt→/runs/{id}/macc-halt-receiptaivp_t4_halt→/runs/{id}/aivp-t4-halt-receiptattestation_gap→/runs/{id}/attestation-gap-receiptstage_error→ No artifact endpoint exists (run record only)
Authentication
Same as every other run endpoint, pass X-Verdifax-Key: $VERDIFAX_KEY.
The orchestrator scopes results to the API key that authored the run, so
one customer cannot retrieve another customer's artifacts.
Response shape
All six return the same envelope:
{
"ok": true,
"run_id": 42,
"<artifact_key>": { ... },
"receipt_anchor": { ... }
}
Where <artifact_key> is one of:
allow_tokendeny_receiptccv_halt_receiptmacc_halt_receiptaivp_t4_halt_receiptattestation_gap_receipt
The five receipt responses carry a sibling receipt_anchor (the receipt's public-log entry) when the receipt was anchored; receipts issued before run 241 have none. The allow_token response has no receipt_anchor.
The artifact object itself is a canonical-bytes record (RFC 8785 + SHA-256)
whose fields are documented in Outcome states.
The terminal hash field is the SHA-256 of the canonical preimage and
is the value verdifax-verify recomputes. Since verifier 0.13.0, verdifax-verify checks the receipt document the API serves, including the receipt's public-log entry; receipts issued before run 241, at 23:11 UTC on 2026-10-16, when receipt anchoring started, carry no entry and are reported as self-consistent only. Receipts anchored under receipt anchor v2 also bind the run number and carry anchor_required: true, which verifier 0.14.0 and later releases read; earlier releases report such receipts as FAILED.
Example, fetching a DenyReceipt
curl -H "X-Verdifax-Key: $VERDIFAX_KEY" \
https://api.verdifax.com/runs/42/deny-receipt
{
"ok": true,
"run_id": 42,
"deny_receipt": {
"anchor_required": true,
"envelope_id": "env-7a3c…",
"fired_rule_id": "mcd-llm-001",
"decision_reason_code": "MCD_SIGNATURE_MATCH",
"policy_hash": "8f1d…",
"evaluation_hash": "b2e0…",
"mcd_finding_hash": "41c6…",
"deny_clock": "2026-04-30T17:23:48.124Z",
"evaluator_version": "pepg-0.3.0",
"version": "vfa.deny_receipt.v1",
"hash": "9e7f…"
},
"receipt_anchor": { ... }
}
The hosted API's built-in policy admits every request, so its only deny is a Malicious Code Defense signature match: fired_rule_id is the matched signature id and mcd_finding_hash is populated. Receipts sealed by the hosted API since run 242 carry "anchor_required": true.
Independent verification
The audit PDF gives a copy-pasteable command for each run. For the five receipts, save the document and verify it; only the path changes:
curl -H "X-Verdifax-Key: $VERDIFAX_KEY" \
https://api.verdifax.com/runs/42/deny-receipt -o receipt.json
verdifax-verify receipt.json
verdifax-verify recomputes the receipt's hash from its own fields and
checks its public-log entry offline: the inclusion proof, the log's
signed timestamp, that a published Verdifax log-signing key logged it,
and that it was logged within 600 seconds of the receipt's own clock.
Exit code 0 means RECEIPT VERIFIED AND ANCHORED. A receipt issued
before receipt anchoring began (run 241) carries no entry and reads
RECEIPT SELF-CONSISTENT ONLY, NOT ANCHORED, exit code 1 unless
--allow-unanchored is passed. Exit code 1 with FAILED means a check
failed, and exit code 2 means the input could not be parsed.
An AllowToken is not checked on its own: it is sealed inside the
allowed run's full record, so verify that record instead
(save GET /runs/{id}/artifacts as bundle.json, then run
verdifax-verify bundle.json).
When you'll see 404
{ "ok": false, "error": "run 42 is \"ok\", not \"pepg_deny\", no deny_receipt exists" }
The error message names both the actual outcome state of the run and the
state required for the requested artifact. The dashboard handles this
automatically by inspecting outcome_kind on the run summary before
choosing which endpoint to call.
Outcome discriminator on run summaries
Every entry in GET /runs and GET /runs/search carries an outcome_kind
field with one of: ok, pepg_deny, ccv_halt, macc_halt,
aivp_t4_halt, attestation_gap, stage_error. Use it to branch on which artifact to fetch without
parsing the manifest.
