Quovalis
PricingDocsSign inGet started

The validation call

The API has one endpoint that does the work: POST /v1/validations. Everything else — fetching stored results, usage, trust-list introspection — reads around it. This page is that call in depth: the request, the result document block by block, and the semantics that matter when you build on it.

The request

curl https://api.quovalis.eu/v1/validations \
  -H "Authorization: Bearer $QUOVALIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "certificate": "-----BEGIN CERTIFICATE-----\n…\n-----END CERTIFICATE-----",
    "chain": ["-----BEGIN CERTIFICATE-----\n…\n-----END CERTIFICATE-----"],
    "policy": "POLICY_EIDAS_QWAC_V1",
    "options": { "checkRevocation": true }
  }'
  • certificate (required) — the leaf certificate, PEM-encoded.
  • chain — up to 10 untrusted intermediates. You do not have to reconstruct a perfect chain: trusted-list-derived and AIA-known intermediates are also used when building the path, so a leaf alone often validates. Sending what your TLS handshake produced is still the most reliable input.
  • policy (required) — POLICY_EIDAS_QWAC_V1 for website authentication certificates, POLICY_EIDAS_QSEALC_V1 for electronic seals (see QWAC vs QSealC). An omitted or unrecognized policy is rejected with 400 invalid-request.
  • options.checkRevocation — default true. With false, the result carries no revocation block at all.

Request bodies are capped at 256 KiB. Unknown members are ignored, not rejected — a misspelled optional key silently falls back to its default — so check spelling against the OpenAPI schema rather than relying on a 400.

The result document

A computed verdict is always an HTTP 200 — including VERDICT_INVALID and VERDICT_INDETERMINATE. Error status codes are reserved for requests the service could not process at all (malformed input, auth, limits — see errors below). Two wire conventions hold everywhere: a field that does not apply is an absent key, never null, and 64-bit integers such as sequenceNumber are JSON strings so no precision is lost.

{
  "id": "0198f3a2-7c11-7000-8000-3f9be1a2c001",
  "verdict": "VERDICT_VALID",
  "policy": "POLICY_EIDAS_QWAC_V1",
  "validatedAt": "2026-07-09T12:00:00Z",
  "certificate": {
    "subject": "CN=bank.example.com,O=Example Bank N.V.,organizationIdentifier=PSDNL-DNB-123456,C=NL",
    "issuer": "CN=Example QTSP QWAC CA,O=Example QTSP,C=NL",
    "serialNumber": "0a:1b:2c:3d:4e:5f",
    "notBefore": "2026-01-01T00:00:00Z",
    "notAfter": "2027-01-01T00:00:00Z",
    "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
  },
  "qualified": {
    "isQualified": true,
    "qcType": "QC_TYPE_WEB",
    "qcStatements": ["QcCompliance", "QcType", "QcPDS"],
    "trustServiceProvider": {
      "name": "Example QTSP",
      "serviceName": "Example QTSP QWAC CA",
      "territory": "NL",
      "serviceStatus": "granted"
    }
  },
  "psd2": {
    "roles": ["PSD2_ROLE_PSP_AS", "PSD2_ROLE_PSP_AI"],
    "ncaId": "NL-DNB",
    "ncaName": "De Nederlandsche Bank",
    "authorizationNumber": "PSDNL-DNB-123456",
    "organizationIdentifier": "PSDNL-DNB-123456"
  },
  "revocation": {
    "status": "REVOCATION_STATUS_GOOD",
    "method": "REVOCATION_METHOD_OCSP",
    "source": "http://ocsp.example-qtsp.example",
    "producedAt": "2026-07-09T11:55:00Z",
    "checkedAt": "2026-07-09T12:00:00Z",
    "cached": false
  },
  "trustList": {
    "territory": "NL",
    "sequenceNumber": "87",
    "snapshotId": "0198f3a2-7c11-7000-8000-3f9be1a2c002"
  }
}

Block by block, with the rules for when each is absent:

  • verdict / subIndication — the tri-state outcome. subIndication names the dominant reason on non-valid verdicts (SUB_INDICATION_REVOKED, SUB_INDICATION_CHAIN_FAILURE, SUB_INDICATION_NOT_QUALIFIED, SUB_INDICATION_REVOCATION_UNAVAILABLE, …) and is absent on a valid one. An indeterminate verdict is never silently upgraded. The full sub-indication table and the semantics of each state are on the tri-state verdict.
  • certificate — the parsed leaf: subject, issuer, serial, validity window and SHA-256 fingerprint, so you can confirm which certificate the verdict is about without re-parsing the PEM yourself.
  • qualified — the qualified-status mapping: isQualified, the parsed qcStatements, the qcType (absent when the certificate declares no known QC type — and also when it declares more than one, since a qualified certificate has exactly one), and the matched trust service provider with its service name, territory and current service status. How this answer is reached is its own page: how qualified status is determined.
  • psd2 — the payment-service roles and the competent authority (name and id) parsed from the PSD2 QCStatement, together with the authorization number carried in the subject's organizationIdentifier; absent when the certificate carries no PSD2 statement. The attributes are read from the certificate; NCA and EBA registers are not cross-checked.
  • revocation — status, method (OCSP or CRL), the evidence source and its producedAt / checkedAt timestamps, and a cached flag telling you whether a previously obtained response was relied on. When fresh OCSP/CRL data is unavailable, a cached response may be relied on for up to 24 hours past its scheduled update time (see the Terms); the timestamps tell you exactly how old the evidence is. Absent when revocation checking was disabled, and when no chain could be built — with no issuer there is nothing to verify revocation evidence against.
  • trustList — the territory, list sequence number and snapshot id the verdict was computed against: the reproducibility anchor. Absent when the chain did not build to any EU trust-list anchor.

Calling semantics

Not idempotent, by design. Every call computes against the current trust-list and revocation state and produces a new, billable validation record. If you want the answer you already got, fetch it instead of re-validating:

curl https://api.quovalis.eu/v1/validations/0198f3a2-7c11-7000-8000-3f9be1a2c001 \
  -H "Authorization: Bearer $QUOVALIS_API_KEY"
  • Results are stored and re-served from the stored record — the same document on every fetch, never recomputed — for up to your plan's retention window. Quotas, rates and retention per plan are on the pricing page.
  • Verdicts are point-in-time. The result document pins its trust-list snapshot and revocation timestamps; a certificate that was valid this morning can be revoked this afternoon. What a stored verdict tells you is what the published data said then — re-validate when the decision matters now.
  • Limits surface in headers. Every authenticated response carries X-RateLimit-*; throttled requests get 429 with Retry-After, and every response an X-Request-Id to quote at support.

Errors

All non-2xx responses are RFC 9457 problem documents (application/problem+json) with a type of urn:quovalis:problem:<suffix>:

Type suffixStatusWhen
invalid-request400Malformed JSON, invalid query parameters, unparseable PEM or an unsupported policy — but never an undocumented member, which is ignored
unauthorized401Missing, unknown or revoked API key
key-expired401Valid key past its expiry date
ip-not-allowed403Source IP outside the key's IP allowlist
insufficient-scope403Key scopes do not cover the operation
not-found404Unknown id (or a resource that is not yours)
request-too-large413Request body over the 256 KiB cap
rate-limited429Rate limit exceeded; Retry-After is set
quota-exceeded429Monthly quota exhausted on a plan that blocks overage
overage-cap-reached429Your monthly overage spend cap is reached
internal500Unhandled failure on our side
upstream-unavailable503A downstream dependency is unavailable; Retry-After is set
overloaded503Platform load shedding (not a tenant limit); Retry-After is set

Problem bodies carry a requestId — quote it when contacting support and we can find the exact request in our logs.

The two monthly-window 429s — quota-exceeded and overage-cap-reached — additionally carry a resetAt extension member: an RFC 3339 timestamp of when the monthly window rolls over. Parse it to back off programmatically rather than scraping the human-readable detail. There is deliberately no Retry-After on these — the wait can be weeks.

Related

  • API quickstart — key setup and the surrounding read endpoints.
  • How qualified status is determined — the procedure behind the qualified block.
  • What is a QWAC? — the certificate type most validations run on.
Previous← The tri-state verdictNextAPI key security →
ContactImprintTermsPrivacyCookiesDPA