Kyndex
Guides

Verifying Document Seals

Use POST /v1/verifications to confirm a verification seal is genuine — no account required.

After the secure enclave processes a document, it generates a verification seal: a cryptographic signature over a payload derived from the document's content hash, identity, timestamp, and verification outcome. The seal lets any third party — without an account, without trusting the platform's infrastructure — confirm that a specific document was processed by an attested enclave and has not been altered since.

Think of it as a notary stamp: the notary (enclave) attests "I examined this document; it was authentic at this moment." Anyone who has the notary's public key can verify that stamp independently, without contacting the notary's office.

Unauthenticated endpoint. POST /v1/verifications requires no Authorization header. Verifiers are third parties, not platform users. Rate limiting applies.

The Three-Party Model

Document verification involves three roles:

  1. Owner — uploads a document. The secure enclave processes it and attaches a seal.
  2. Verifier — a third party (auditor, regulator, counterparty) who receives the document and seal from the owner through any channel.
  3. Server — provides the public verification endpoint. The verifier calls it, but does not need to trust the platform to interpret the result.

The key property: the verifier independently checks a cryptographic signature using the platform's public key. If the server were to tamper with the stored seal or swap signatures, the check would fail. The server cannot forge a valid seal retroactively.

The Signature Algorithm

Seals are produced using ECDSA with SHA-256 over the NIST P-256 curve, backed by a hardware-protected platform signing key held in the key management service. The signing key never leaves the key management service boundary — signing and verification happen inside the service, not in application memory.

ECDSA with SHA-256 is the current signing algorithm. The intended design is a hybrid ML-DSA-65 + Ed25519 scheme, providing post-quantum resistance for long-lived seals. The hybrid path is tracked as engineering gap #24 and is not yet wired. The algorithm field in the response reflects the actual algorithm in use.

Where The Seal Comes From

Fetch the document detail endpoint to retrieve the seal fields:

curl https://api.kyndex.co/v1/documents/<document-id> \
  -H 'Authorization: Bearer <access_token>'

The response includes:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "processed",
  "seal_encrypted": "<base64-encrypted-seal-blob>",
  "seal_commitment": "<base64-commitment-hash>",
  ...
}

Both seal_encrypted and seal_commitment are null until the processing pipeline produces a seal. They may remain null on processed documents if the processing path did not complete verification — treat null as "no seal available," not as a failure.

The Two Seal Fields

The seal is stored as two complementary values:

  • seal_encrypted — the complete VerificationSeal structure, encrypted with the document's DEK. Contains the content hash, document identity, timestamp, verification outcome, and platform signature. Only the document owner (or a grant holder) can decrypt it.
  • seal_commitment — a SHA-256 hash of the complete JSON-serialized seal, stored unencrypted in the database. It cannot reconstruct the seal, but it proves the seal existed in a specific state at a specific time. If seal_encrypted were replaced after the fact, the stored commitment would no longer match.

The owner decrypts seal_encrypted using the document key, then extracts the signing payload and platform signature to share with the verifier. The verifier submits these two values to POST /v1/verifications.

The Request

curl -X POST https://api.kyndex.co/v1/verifications \
  -H 'Content-Type: application/json' \
  -d '{
    "data": "<base64-signing-payload>",
    "signature": "<base64-platform-signature>"
  }'

Request Fields

FieldTypeDescription
database64 stringThe signing payload extracted from the decrypted seal
signaturebase64 stringThe DER-encoded ECDSA platform signature from the decrypted seal

Both fields must be standard base64 (not URL-safe). The server SHA-256 hashes data before passing it to the key management service — submit the signing payload bytes, not a pre-hashed digest.

The Response

200 OK:

{
  "valid": true,
  "algorithm": "ECDSA_SHA_256"
}
FieldTypeDescription
validbooleanWhether the signature verified successfully
algorithmstringSigning algorithm used — reflects the actual signing key

The endpoint always returns 200 when the request is well-formed. The valid field carries the result:

  • valid: true — the signature is genuine. The signing payload was produced by the platform signing key. The document content matches what the enclave saw at processing time.
  • valid: false — the signature does not verify. The data has been modified, the signature bytes are wrong, or the two values were not produced together. Treat the document as tampered.

What A Valid Seal Proves

A valid: true response makes three assertions:

  1. Enclave provenance — the seal was generated by an attested enclave running verified software. A tampered or impersonated enclave cannot access the platform signing key and therefore cannot produce a valid seal.
  2. Content integrity — the signing payload binds the document's content hash at processing time. If a single byte of the document changes after processing, the seal no longer matches.
  3. Non-transferability — the payload includes the document's identity. The seal cannot be re-used to vouch for a different document.

A valid: false response does not distinguish between a tampered document and corrupted seal transmission. The verifier should reject the document and request a fresh copy from the owner.

Error Cases

All errors follow RFC 9457 (Content-Type: application/problem+json):

{
  "type": "https://api.kyndex.co/errors/INVALID_REQUEST",
  "title": "Bad Request",
  "status": 400,
  "detail": "Invalid base64 in data field",
  "instance": "/v1/verifications"
}
StatusCauseResolution
400Malformed base64 in data or signatureVerify the base64 encoding — standard alphabet, valid padding
429Rate limit exceededBack off and retry
500Key management service verification call failedTransient infrastructure error; retry with exponential backoff

A 500 does not indicate an invalid seal — it indicates the check could not be completed. Retry before treating the seal as invalid.

Integration Checklist

Before shipping a verifier integration, confirm:

  • Your base64 decoder handles standard padding (= suffix); reject URL-safe input at the boundary.
  • You treat valid: false and 5xx differently: false = reject the document; 5xx = retry.
  • You enforce a maximum retry budget for 500s (3 attempts with exponential backoff is reasonable).
  • You do not cache valid: true responses indefinitely — if the document owner later indicates the seal should be re-checked, re-verify.
  • You handle null seal fields gracefully — not all processed documents are guaranteed to have a seal.

On this page