The tri-state verdict
Every validation answers with exactly one of three verdicts — VERDICT_VALID, VERDICT_INVALID or VERDICT_INDETERMINATE — modelled on ETSI EN 319 102-1 and adapted to certificate-only validation (ETSI-style, not a claim of full EN 319 102-1 conformance). The third state is not a hedge — it is the honest answer when the data a verdict would need could not be obtained or evaluated.
The three states
VERDICT_VALID— every check passed: the chain builds to a grantedCA/QCtrusted-list service, the certificate satisfies the requested policy, and revocation (when checked) came back good. Valid is relative to the trust-list snapshot and revocation evidence pinned in the result document — evidence that may be a cached OCSP/CRL response during issuer outages; itsproducedAt,checkedAtandcachedfields make its age explicit.VERDICT_INVALID— a definitive failure: something checkable was checked and failed, and no missing data could change the answer.VERDICT_INDETERMINATE— the verdict could not be determined with confidence: an input the decision needs was unavailable (no revocation answer, a stale trusted list) or not evaluable (an unreadable extension, a trusted-list override that cannot be applied cleanly).
Valid is scoped to the checks the service performs: chain building, trusted-list qualification, the policy's QC-type rules and revocation. It is not a full eIDAS Annex IV content audit — subject identity, address and domain-name content are not evaluated — and the strict QWAC web-profile checks (serverAuth key usage, a subjectAltName) are an optional mode that is not enabled by default.
A computed verdict — including the two non-valid ones — is always an HTTP 200. Error status codes mean the request itself could not be processed; see the validation call.
Why indeterminate is not invalid
An unreachable OCSP responder does not make a certificate revoked, and a trusted list past its freshness window does not make one unqualified. A validator that collapses those unknowns into invalid manufactures false failures; one that collapses them into valid is guessing. Both collapses destroy exactly the information a relying party needs to apply its own risk policy — which is why the two answers stay distinct, and why an indeterminate result is never silently upgraded to valid or downgraded to invalid.
What to do with an indeterminate answer is a policy decision that belongs to you, not to the validator: block, retry later, or accept with compensating controls. The subIndication tells you which input was missing, so the policy can be specific — a SUB_INDICATION_REVOCATION_UNAVAILABLE is often worth a retry once the issuer's OCSP/CRL infrastructure recovers, while a SUB_INDICATION_TRUST_LIST_STALE can be watched via GET /v1/trustlist/status (see trusted lists and the LOTL).
Sub-indications
Every non-valid verdict carries a subIndication naming the dominant reason; a valid one carries none — the field is absent, never null.
With VERDICT_INVALID
SUB_INDICATION_EXPIRED- The certificate's notAfter is in the past.
SUB_INDICATION_NOT_YET_VALID- The certificate's notBefore is in the future.
SUB_INDICATION_REVOKED- Fresh OCSP or CRL evidence says revoked.
SUB_INDICATION_CHAIN_FAILURE- No path could be built to any trusted-list anchor.
SUB_INDICATION_NOT_QUALIFIED- The chain builds, but the certificate is not EU-qualified: the anchor is not a granted CA/QC service, the certificate's statements combined with the trusted-list overrides do not qualify it, or it declares qualification under a named country's legislation rather than under eIDAS.
SUB_INDICATION_WRONG_QC_TYPE- Qualified, but not the certificate type the requested policy requires — e.g. a QSealC validated under
POLICY_EIDAS_QWAC_V1. Under the optional strict QWAC web profile (not enabled by default) this also covers a missingserverAuthkey usage orsubjectAltName.
With VERDICT_INDETERMINATE
SUB_INDICATION_REVOCATION_UNAVAILABLE- Revocation was requested but no fresh or cached OCSP/CRL answer could be obtained within budget.
SUB_INDICATION_TRUST_LIST_STALE- The trust-list snapshot behind the answer is past its freshness window.
SUB_INDICATION_PARSE_ERROR- The material decodes as X.509 but a critical part could not be parsed.
SUB_INDICATION_QUALIFICATION_UNDETERMINED- The qualification input itself is unknowable — an applicable trusted-list qualification override could not be fully evaluated, or the certificate declares the policy's QC type together with another where the standard allows exactly one. Deliberately left undetermined rather than guessed.
SUB_INDICATION_TSP_NAME_INCONSISTENT- The trusted list and the certificate name different organizations for the issuing CA (an optional strict check, not enabled by default).
One dominant reason
A certificate can fail in several ways at once — expired and revoked, revoked and issued by a withdrawn service. The verdict engine applies a fixed precedence and reports the single dominant reason rather than a list. Two rules in that ordering are worth knowing when you build on it: SUB_INDICATION_REVOKED outranks everything else, and a definitive failure that does not depend on qualification outranks any indeterminate — an expired certificate whose OCSP responder is also down is reported as SUB_INDICATION_EXPIRED, not as SUB_INDICATION_REVOCATION_UNAVAILABLE, because the missing data cannot change that answer.
Gate on the verdict, not on isQualified
The qualified block reports what the certificate is; the verdict reports whether it passed the policy you asked for. The two can disagree legitimately — a perfectly qualified electronic-seal certificate validated under POLICY_EIDAS_QWAC_V1 is:
{
"verdict": "VERDICT_INVALID",
"subIndication": "SUB_INDICATION_WRONG_QC_TYPE",
"policy": "POLICY_EIDAS_QWAC_V1",
"qualified": {
"isQualified": true,
"qcType": "QC_TYPE_ESEAL",
"trustServiceProvider": { "name": "Example QTSP", "territory": "NL", "serviceStatus": "granted" }
},
…
}Code that accepts on qualified.isQualified alone would wave this certificate through. Branch on verdict; read qualified, revocation and trustList as the explanation, not the authorization. How the qualified answer itself is reached is covered on how qualified status is determined.
A verdict is a technical assessment against the published trust-list and revocation data pinned in the result document — see the Terms for the documented non-claims.
Related
- The validation call — the result document around the verdict, block by block.
- How qualified status is determined — the procedure behind the
qualifiedblock. - Trusted lists and the LOTL — the data every verdict is computed against.
- API quickstart — from zero to a verdict in three steps.