Proofs And Certificates
Operate proof submission, proof lifecycle, certificate artifacts, revocation, and public verification identifiers.
Proofs And Certificates
Proofs are .der files produced by the wipe agent. The backend stores the raw
proof object before processing and uses asynchronous workers to validate,
decrypt, sign, certify, and optionally anchor the result.
Submission Routes
| Route | Auth | Use |
|---|---|---|
POST /api/v1/proofs | CLIENT_ADMIN, CLIENT_TECH, or generic proofs:write API key | Submit one multipart .der proof. |
POST /api/v1/proofs/bulk | CLIENT_ADMIN, CLIENT_TECH, or generic proofs:write API key | Submit up to 100 files or a ZIP archive, max 500 MB. |
POST /ingest/v1/proofs | Enrolled-agent API key with proofs:write | Submit one raw .der body from an enrolled agent. |
GET /ingest/v1/proofs/{id} | Enrolled-agent API key with proofs:read | Poll the status of an agent-owned proof. |
Protected writes require Idempotency-Key. The unit proof size limit is 5 MB.
The local rate limits are per authenticated principal or agent key: 100 unit
submissions per hour and 500 batch submissions per hour. Each quota is a
separate counter, shared across all API and ingest replicas through the
database (rate_limit_windows, migration 0025); a 429 carries Retry-After.
The only value the backend accepts as a successful wipe, for
disks[].wipe_status and wipe.result, is SUCCESS (case-insensitive). A
disk without a wipe_status inherits wipe.result. Older synonyms such as
true, wiped, ok, passed or completed are treated as failures, and a
proof with no successful disk is REJECTED; check agent fleets still emitting
them before upgrading.
Proof Statuses
| Status | Meaning | Operator action |
|---|---|---|
RECEIVED | Stored and queued. | Watch queue depth if it persists. |
VALIDATING | Worker is validating proof envelope, agent trust, schema, and version. | Inspect worker logs if stalled. |
GENERATING_PDF | Certificate PDF is being rendered. | Check object storage and signer if failures appear. |
SIGNING | HMAC/PAdES/receipt signing is running. | Check signer readiness and key IDs. |
ANCHORING | Anchor worker is processing chain metadata. | Check chain worker and blockchain configuration. |
CERTIFIED | Certificate was produced with anchor data. | No action. |
CERTIFIED_NO_ANCHOR | Certificate was produced without active anchor data. | Accept only when product policy allows. |
AWAITING_LICENSE | Proof is valid but quota/licensing is unavailable. | Import/allocate licenses, then retry. |
FAILED | Recoverable dependency or processing failure. | Fix root cause, then retry. |
REJECTED | Terminal validation failure. | Do not replay unless validation policy was wrong. |
ABANDONED | Operator abandoned a failed proof. | Keep audit context. |
Lifecycle Actions
| Action | Route | Role |
|---|---|---|
| List proofs | GET /api/v1/proofs | CLIENT_ADMIN, CLIENT_TECH, AUDITOR |
| Read proof | GET /api/v1/proofs/{id} | CLIENT_ADMIN, CLIENT_TECH, AUDITOR, or proofs:read where accepted |
| Read status | GET /api/v1/proofs/{id}/status | CLIENT_ADMIN, CLIENT_TECH, AUDITOR, or proofs:read where accepted |
| Retry | POST /api/v1/proofs/{id}/retry | CLIENT_ADMIN |
| Full restart | POST /api/v1/proofs/{id}/full-restart | CLIENT_ADMIN |
| Abandon | POST /api/v1/proofs/{id}/abandon | CLIENT_ADMIN |
retry, full-restart, and abandon require recent MFA when
SENSITIVE_ACTION_MFA_MAX_AGE is enabled.
Rejection Codes
When a proof transitions to REJECTED, the API exposes two fields:
rejection_reason— free-text description of the failure, written by the pipeline step that detected it. Its wording may change between releases.rejection_code— stable, machine-readable identifier that ISOs and integrations can act on without parsing text. The field is empty for proofs rejected before migration 0026 and for every non-REJECTEDstatus.
| Code | Meaning |
|---|---|
no_successful_disk | No disk of the session reports SUCCESS; the portal certifies nothing (portal rule, outside the shared schema). |
payload_not_json | The decrypted body is not a JSON document. |
payload_invalid | The document does not satisfy the portal’s legacy (pre-v4) payload rules; rejection_reason says which field. |
schema_invalid | schema.Decode or schema.Validate of the shared module refused the v4 report (shape, enumeration, form, bound). |
schema_version_unknown | schema_version is not the one the shared module carries (schema.ErrVersion). |
signature_missing | The CMS envelope carries no signature (envelope.ErrUnsigned). |
signature_invalid | The signature does not verify, or the signer names no certificate (envelope.ErrSignature, ErrCertificate, ErrMessageDigest; legacy inline agent_signature failures). |
untrusted_signer | The signer certificate does not chain to a trusted root (envelope.ErrUntrusted). |
identity_refused | The ISO identity is unknown, not ENROLLED, or revoked (envelope.ErrIdentity). |
envelope_invalid | Any other structural refusal of the CMS envelope (envelope.ErrSignedData, ErrAlgorithm, ErrAttributes, ErrSignerKey, ErrEnveloped, ErrNotCanonical, ErrIdentifier). |
report_digest_mismatch | The decrypted report is not the one the signed report-sha256 names (envelope.ErrReportDigest). |
session_binding_mismatch | The report’s wipe_session_id or iso_id differ from the signed attributes (envelope.ErrBinding). |
organization_mismatch | The signer identity or the issuer member is bound to another Organisation than the submitter’s. |
replay | Another proof of the same Organisation with the same wipe_session_id was already accepted (uniqueness rule). |
stored_hash_mismatch | The stored .der no longer matches the SHA-256 recorded at submission. |
Codes are added, never renamed. rejection_reason remains free text and may carry additional diagnostic detail beyond what the code conveys.
Certificate Routes
| Action | Route | Role |
|---|---|---|
| List certificates | GET /api/v1/certificates | CLIENT_ADMIN, CLIENT_TECH, AUDITOR |
| Read metadata | GET /api/v1/certificates/{id} | CLIENT_ADMIN, CLIENT_TECH, AUDITOR |
| Download PDF | GET /api/v1/certificates/{id}/pdf | CLIENT_ADMIN, CLIENT_TECH, AUDITOR |
| Download canonical JSON | GET /api/v1/certificates/{id}/canonical | CLIENT_ADMIN, CLIENT_TECH, AUDITOR |
| Revoke | POST /api/v1/certificates/{id}/revoke | CLIENT_ADMIN |
Certificate statuses are CERTIFIED, CERTIFIED_NO_ANCHOR, and REVOKED.
Revocation requires an audit reason and recent MFA when configured.
Canonical Object Schema
The canonical JSON carries a schema member naming its version:
| Version | Content |
|---|---|
wipe.certificate.v1 | Pre-anchor-identity documents. |
wipe.certificate.v2 | Adds the anchor.chain_id logical chain identity. |
wipe.certificate.v3 | evidence is the RAW agent proof document. |
In wipe.certificate.v3 the evidence member is the decrypted proof document
itself, minus its agent_signature member and canonicalized with RFC 8785
(JCS) — byte-for-byte the payload the agent signature covers. Fields the portal
does not model, empty arrays, explicit nulls and numbers as the agent wrote
them are all preserved, so an agent can replay its own signature check against
the certificate.
Certificates issued under v1 and v2 keep verifying: verification recomputes
the hash from the stored canonical JSON and never rebuilds the document.
Public Verification
Public verification is available through:
| Route | Input |
|---|---|
GET /verify or GET /api/v1/public/verify | Query parameters. |
POST /verify or POST /api/v1/public/verify | JSON body, query parameters, or both. |
Supported identifiers are code, certificate_id, canonical_hash, and
tx_hash. When more than one identifier is supplied, they must refer to the
same certificate or the result is IDENTIFIER_MISMATCH.
Public responses never include tenant ID, organization ID, proof ID, internal storage keys, canonical JSON, HMAC value, or PDF object keys.
Operator Checks
| Symptom | First checks |
|---|---|
Proofs remain RECEIVED | proofs.validated queue, proof worker health, DB connectivity. |
Proofs become AWAITING_LICENSE | Active grants, allocation scope, user/org quota, grant validity dates. |
Proofs become FAILED | Signer, object storage, PAdES/TSA, malformed environment configuration. |
Certificates are CERTIFIED_NO_ANCHOR | BLOCKCHAIN_ENABLED, chain registry, anchor worker, Hedera readiness. |
| Public verification returns invalid/tampered | PDF/canonical/HMAC mismatch, revoked certificate, chain lookup failure, wrong identifier. |