Verification API
Reference
Verification API
Read-only endpoints for anyone checking a Nyvarra certificate. No key, no account. The same checks run here as on the verify page, so your software and a person checking by hand always get the same answer. Certificate PDF, signed credential and Open Badge downloads require recipient or issuer sign-in.
{code} in a path is either the certificate's serial (NV-000142) or its credential ID (NV-7KQ2M9XHCP4WRTZB-1187). Both are printed on the certificate and in its QR code.
The verification
Every verify response carries a verification object. Its overall_status is the answer. The other fields show how it was reached, for your logs and audits.
| overall_status | Shown to people as | Meaning |
|---|---|---|
verified | Genuine | The signature, the record and the issuer's key all check out, and the certificate is current. |
expired | Expired | Genuine, but past the end date the issuer set. Good only as proof of what was true until then. |
superseded | Replaced | The issuer corrected it. replacement_certificate holds the version that counts now. |
revoked | Withdrawn | The issuer withdrew it. revoked_at and revocation_reason say when and why. |
tampered | Doesn't match | The record no longer matches what the issuer signed, or the signing key doesn't match the registry. |
key_revoked | Key withdrawn | The key that signed it was withdrawn. It can't be confirmed until the issuer issues it again. |
key_compromised | Key withdrawn | As key_revoked, after a security problem with the key. |
Accept only verified. Treat any value not in this table as unconfirmed; new ones may be added.
Fields
cryptographic_validboolean- All of the signature checks below passed. When false, overall_status is tampered.
signature_validboolean- The Ed25519 signature verifies against the issuer's key in Nyvarra's registry, never a key carried inside the certificate.
payload_matches_proofboolean- The stored record is exactly what was signed.
payload_hash_matchesboolean- The record's SHA-256 matches the hash stored at issue.
issuer_claims_matchboolean- The signed issuer, recipient and credential IDs match the record.
key_matches_registryboolean- The signing key is the one registered to this issuer.
signing_key_statusstring- The key's state now:
active,rotating,retired(replaced by a newer key, still valid for what it signed),revokedorcompromised. revoked · superseded · expiredboolean- The certificate's lifecycle, as separate flags.
transferredboolean- The certificate was issued on the issuer's own system and its record later moved to Nyvarra. Nyvarra's custody attestation is checked too.
signature_errorstring | null- Why a signature check failed, in a sentence. Null when it passed.
verified_atstring- When this check ran.
{
"overall_status": "verified",
"cryptographic_valid": true,
"signature_valid": true,
"payload_matches_proof": true,
"payload_hash_matches": true,
"issuer_claims_match": true,
"key_trusted": true,
"key_matches_registry": true,
"signing_key_status": "active",
"signing_key_fingerprint": "9e04b8…5c1d",
"revoked": false,
"superseded": false,
"expired": false,
"transferred": false,
"signature_error": null,
"verified_at": "2026-10-07T08:12:44.120Z"
}Verify a certificate
GET/api/public/credentials/verify/{code}
Looks up the certificate, runs every check and returns the public record with the result. Each call is added to the certificate's check count.
Path parameters
codestringrequired- The serial or credential ID. Case doesn't matter.
Returns
certificateobject- The public record: recipient name, what it was for, issuer, dates, verification links and its hashes. Private data such as the recipient's email or registration number, and Nyvarra's internal IDs, are never included. Certificate export URLs are always
nullin public responses. Recipients download from their signed-in profiles; authorized issuer staff can also download. certificate.issuer.assurance_labelstring- What Nyvarra has confirmed about the issuer, in words, such as “Official account of …” or “Organization domain verified”. See the trust model.
verificationobject- The result, described above.
replacement_certificateobject | null- When the certificate was replaced, the corrected one, in the same shape as certificate.
Responses
- 200
- The check ran. Read verification.overall_status.
- 404
- No certificate has that serial or ID.
- 429
- Rate limited.
- 503
- The check didn't complete. Not a pass.
Rate limit: 240 requests a minute
curl https://nyvarra.app/api/public/credentials/verify/NV-000142{
"success": true,
"certificate": {
"serial": "NV-000142",
"credential_id": "NV-7KQ2M9XHCP4WRTZB-1187",
"status": "issued",
"visibility": "public",
"issued_at": "2026-09-14T09:30:00.000Z",
"expires_at": null,
"revoked_at": null,
"revocation_reason": null,
"verification_url": "https://nyvarra.app/verify/NV-7KQ2M9XHCP4WRTZB-1187",
"pdf_url": null,
"credential_url": null,
"open_badge_url": null,
"verification_receipt_url": "https://nyvarra.app/api/public/credentials/NV-7KQ2M9XHCP4WRTZB-1187/verification-receipt",
"artifact_manifest_url": null,
"issuance_mode": "native",
"transfer": null,
"recipient": {
"full_name": "Ayesha Siddiqui"
},
"event": {
"title": "Basic Life Support Workshop",
"achievement": "Basic Life Support Workshop",
"role": null,
"description": "Hands-on adult and paediatric BLS.",
"attendance": null,
"credential_type": "academic_event",
"evidence": null,
"cpd": { "hours": 4, "kind": "CME", "accreditation": null }
},
"issuer": {
"name": "Example Medical College",
"slug": "example-medical-college",
"did": "did:web:nyvarra.app:issuers:example-medical-college",
"verified_domain": "example.edu.pk",
"kind": "organisation",
"assurance": "domain_verified",
"official_of": null,
"assurance_label": "Organization domain verified"
},
"hashes": {
"payload_sha256": "3b9f0c…e21a",
"pdf_sha256": "a41d77…09fc",
"template_fingerprint": "c0de51…7b33"
}
},
"verification": {
"overall_status": "verified",
"cryptographic_valid": true,
"signature_valid": true,
"payload_matches_proof": true,
"payload_hash_matches": true,
"issuer_claims_match": true,
"key_trusted": true,
"key_matches_registry": true,
"signing_key_status": "active",
"signing_key_fingerprint": "9e04b8…5c1d",
"revoked": false,
"superseded": false,
"expired": false,
"transferred": false,
"signature_error": null,
"verified_at": "2026-10-07T08:12:44.120Z"
},
"replacement_certificate": null
}Verify by PDF file
GET/api/public/credentials/file/{sha256}
Checks a PDF someone sent you. Hash the file yourself and send only its SHA-256; the file never leaves your system. A match means the file is, byte for byte, the PDF that was issued.
A 404 doesn't always mean a fake: a file that was printed and scanned, re-saved or compressed has different bytes. Check those by the serial printed on them.
Path parameters
sha256stringrequired- The SHA-256 of the whole PDF file, as 64 hexadecimal characters.
Returns
file.matches_issued_pdfboolean- True when a certificate was issued as these exact bytes.
certificate · verification · replacement_certificateobject- As for Verify a certificate.
Responses
- 200
- The file is an issued certificate. Still read verification.overall_status: it may since have been withdrawn.
- 400
- The fingerprint isn't 64 hexadecimal characters.
- 404
- No certificate was issued as this exact file.
- 503
- The check didn't complete.
Rate limit: 120 requests a minute
SHA=$(shasum -a 256 certificate.pdf | cut -d' ' -f1)
curl https://nyvarra.app/api/public/credentials/file/$SHA{
"success": true,
"file": {
"sha256": "a41d77…09fc",
"matches_issued_pdf": true
},
"certificate": { "serial": "NV-000142", "…": "…" },
"verification": { "overall_status": "verified", "…": "…" },
"replacement_certificate": null
}{
"success": false,
"error": "No certificate was issued as this exact file.",
"file": { "sha256": "5e0c1b…aa90", "matches_issued_pdf": false }
}Certificate PDF
GET/api/public/credentials/{code}/pdf
Requires a signed-in recipient or authorized member of the approved issuer, with two-step sign-in completed where enabled. The legacy URL is retained; the /public/ path does not grant public access. Use the download controls in your profile or issuer workspace.
The certificate as a PDF, identical to the one issued. Before it's sent, Nyvarra checks it against the pdf_sha256 recorded at issue.
Responses
- 200
application/pdf- 401
- Sign in or complete two-step authentication.
- 404
- Not found or not authorized for this certificate.
- 410
- Withdrawn or replaced: files are no longer served. The verify endpoint shows the current status.
- 503
- Unavailable just now.
Rate limit: 30 requests a minute
// Run on nyvarra.app after signing in as the recipient or issuer.
const response = await fetch("/api/public/credentials/NV-000142/pdf", {
credentials: "same-origin",
});
if (!response.ok) throw new Error(`Download failed: ${response.status}`);
const file = await response.blob();Signed credential
GET/api/public/credentials/{code}/credential
Requires a signed-in recipient or authorized member of the approved issuer, with two-step sign-in completed where enabled. The legacy URL is retained; the /public/ path does not grant public access. Use the download controls in your profile or issuer workspace.
The signed record itself, as JSON-LD, with its proof. Use it to check the signature with your own tools, or to keep an exact copy.
Responses
- 200
application/ld+json- 401
- Sign in or complete two-step authentication.
- 404
- Not found or not authorized for this certificate.
- 410
- Withdrawn or replaced.
- 503
- Unavailable just now.
Rate limit: 240 requests a minute
// Run on nyvarra.app after signing in as the recipient or issuer.
const response = await fetch("/api/public/credentials/NV-000142/credential", {
credentials: "same-origin",
});
if (!response.ok) throw new Error(`Download failed: ${response.status}`);
const credential = await response.text();Open Badge export
GET/api/public/credentials/{code}/open-badge
Requires a signed-in recipient or authorized member of the approved issuer, with two-step sign-in completed where enabled. The legacy URL is retained; the /public/ path does not grant public access. Use the download controls in your profile or issuer workspace.
The certificate as an Open Badges 3.0 verifiable credential, for wallets and learning records. Ask for application/jwt in Accept (or add ?format=jwt) for a compact VC-JWT; otherwise you get the exact signed JSON-LD document. Details are in Open Badges 3.0.
Responses
- 200
application/ld+jsonorapplication/jwt- 401
- Sign in or complete two-step authentication.
- 404
- Not found or not authorized for this certificate.
- 409
- This certificate can't be exported as a JWT. Ask for JSON-LD.
- 410
- Withdrawn or replaced.
- 503
- Unavailable just now.
Rate limit: 60 requests a minute
// Run on nyvarra.app after signing in as the recipient or issuer.
const response = await fetch("/api/public/credentials/NV-000142/open-badge", {
credentials: "same-origin",
headers: { Accept: "application/ld+json" },
});
if (!response.ok) throw new Error(`Download failed: ${response.status}`);
const credential = await response.text();// Run on nyvarra.app after signing in as the recipient or issuer.
const response = await fetch("/api/public/credentials/NV-000142/open-badge", {
credentials: "same-origin",
headers: { Accept: "application/jwt" },
});
if (!response.ok) throw new Error(`Download failed: ${response.status}`);
const credential = await response.text();Verification receipt
GET/api/public/credentials/{code}/verification-receipt
A one-page PDF recording a check made now: the result, each check, the hashes, the issuer and the time. File it with an application or a personnel record as evidence of what you checked and when. It counts as a check.
Responses
- 200
application/pdf- 404
- Not found.
- 503
- Unavailable just now.
Rate limit: 30 requests a minute
curl https://nyvarra.app/api/public/credentials/NV-000142/verification-receipt \
-o NV-000142-receipt.pdfArtifact manifest
GET/api/public/credentials/{code}/artifact-manifest
For certificates an issuer designed elsewhere and sealed on Nyvarra: the signed manifest that ties the issuer's original file to the final PDF. certificate.artifact_manifest_url is set only when one exists.
Responses
- 200
- The manifest, its signature and whether each check passes.
- 404
- Not found, or this certificate has no manifest.
- 503
- Unavailable just now.
Rate limit: 120 requests a minute
{
"success": true,
"artifact_binding": {
"valid": true,
"signature_valid": true,
"canonical_hash_matches": true,
"key_fingerprint_matches": true,
"key_status": "active"
},
"manifest": { "…": "source and final PDF hashes, serial, issuer" },
"proof": {
"type": "Ed25519ArtifactManifestSignature2026",
"signature": "…",
"canonical_sha256": "…",
"signing_key_id": "…",
"signing_key_version": 3,
"signing_key_fingerprint": "9e04b8…5c1d"
}
}List issuers
GET/api/public/issuers
Approved issuers with a public profile, searchable by name.
Query parameters
qstring- Search by name, up to 120 characters. Without it, up to 24 issuers are listed.
Rate limit: 120 requests a minute
curl https://nyvarra.app/api/public/issuers?q=medical{
"success": true,
"issuers": [
{
"name": "Example Medical College",
"slug": "example-medical-college",
"public_url": "https://nyvarra.app/issuers/example-medical-college",
"website": "https://example.edu.pk",
"verified_domain": "example.edu.pk",
"assurance_label": "Organization domain verified",
"city": "Lahore",
"country": "Pakistan",
"approved_at": "2026-08-02T11:04:00.000Z",
"stats": { "issued_count": 1284, "active_program_count": 6, "…": "…" }
}
]
}Retrieve an issuer
GET/api/public/issuers/{slug}
An issuer's public profile: who they are, what Nyvarra has confirmed about them, their programs and counts, and the fingerprints of the keys they sign with.
Path parameters
slugstringrequired- From
certificate.issuer.slugor the issuer's page address.
Responses
- 200
- The profile.
- 404
- No approved issuer has that slug.
- 503
- Unavailable just now.
Rate limit: 180 requests a minute
curl https://nyvarra.app/api/public/issuers/example-medical-college{
"success": true,
"issuer": {
"issuer": {
"name": "Example Medical College",
"slug": "example-medical-college",
"verified_domain": "example.edu.pk",
"assurance_label": "Organization domain verified",
"legal_name": "Example Medical College",
"country": "Pakistan",
"approved_at": "2026-08-02T11:04:00.000Z",
"key_transparency": { "…": "current and past signing key fingerprints" }
},
"stats": {
"program_count": 9,
"active_program_count": 6,
"issued_count": 1284,
"active_credential_count": 1271,
"verification_count": 3310,
"last_issued_at": "2026-10-03T07:45:00.000Z"
},
"catalog": [ "…" ]
}
}Retrieve a Passport
GET/api/public/passports/{handle}
A person's public Passport: the certificates they've chosen to show, and Open Badges they imported from elsewhere. Only what the holder made public is returned.
Query parameters
verification1- Include a verification object for every Nyvarra certificate on the Passport.
Responses
- 200
- The Passport.
- 404
- No public Passport has that handle.
- 503
- Unavailable just now.
Rate limit: 180 requests a minute
curl https://nyvarra.app/api/public/passports/ayesha?verification=1{
"success": true,
"passport": {
"profile": {
"handle": "ayesha",
"display_name": "Ayesha Siddiqui",
"headline": "House officer, Lahore",
"verification_status": "active"
},
"links": {
"public_url": "https://nyvarra.app/u/ayesha",
"api_url": "https://nyvarra.app/api/public/passports/ayesha"
},
"stats": { "credential_count": 7, "profile_completeness": 86 },
"credentials": [ "…" ],
"external_credentials": [
{
"name": "Cloud Practitioner",
"issuer": "Example Training Ltd",
"proof_status": "verified",
"proof_method": "eddsa-jcs-2022",
"source_format": "open_badge_3_jsonld"
}
]
}
}