Skip to main content
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_statusShown to people asMeaning
verifiedGenuineThe signature, the record and the issuer's key all check out, and the certificate is current.
expiredExpiredGenuine, but past the end date the issuer set. Good only as proof of what was true until then.
supersededReplacedThe issuer corrected it. replacement_certificate holds the version that counts now.
revokedWithdrawnThe issuer withdrew it. revoked_at and revocation_reason say when and why.
tamperedDoesn't matchThe record no longer matches what the issuer signed, or the signing key doesn't match the registry.
key_revokedKey withdrawnThe key that signed it was withdrawn. It can't be confirmed until the issuer issues it again.
key_compromisedKey withdrawnAs 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), revoked or compromised.
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.
The verification object
{
  "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 null in 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

Request
curl https://nyvarra.app/api/public/credentials/verify/NV-000142
200 OK
{
  "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

Request
SHA=$(shasum -a 256 certificate.pdf | cut -d' ' -f1)
curl https://nyvarra.app/api/public/credentials/file/$SHA
200 OK
{
  "success": true,
  "file": {
    "sha256": "a41d77…09fc",
    "matches_issued_pdf": true
  },
  "certificate": { "serial": "NV-000142", "…": "…" },
  "verification": { "overall_status": "verified", "…": "…" },
  "replacement_certificate": null
}
404 Not Found
{
  "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

Request
// 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

Request
// 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+json or application/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

JSON-LD
// 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();
VC-JWT
// 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

Request
curl https://nyvarra.app/api/public/credentials/NV-000142/verification-receipt \
  -o NV-000142-receipt.pdf

Artifact 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

200 OK
{
  "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

Request
curl https://nyvarra.app/api/public/issuers?q=medical
200 OK
{
  "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.slug or 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

Request
curl https://nyvarra.app/api/public/issuers/example-medical-college
200 OK
{
  "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

Request
curl https://nyvarra.app/api/public/passports/ayesha?verification=1
200 OK
{
  "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"
      }
    ]
  }
}