Anyone can photoshop a PDF certificate. If your course, workshop, or training program emails
completion certificates as PDFs or PNGs, nothing stops a recipient from editing the name, the date,
or the course title — and nothing lets an employer check whether the certificate is real.
Making a completion certificate verifiable takes three things:
- A server-side record of what was actually issued (issuer, course, recipient, date), created at issuance time — not just pixels.
- A cryptographic signature over that record (so any alteration is detectable).
- A public verify page anyone can open — no account, no app — to check the certificate against the authoritative record.
This post shows the fastest programmatic route we know, then covers the alternatives.
Disclosure: we built Attestify at Novadyne — it's the free API used in the walkthrough below.
The alternatives section is honest about when you'd pick something else.
Issue a verifiable certificate with one HTTP call
Attestify is a free API (no signup, no API key) where every certificate gets a permanent,
tamper-evident public verify page backed by an Ed25519-signed server-side record:
curl -X POST https://attestify.novadyne.ai/cert/issue \
-H "Content-Type: application/json" \
-d '{"issuer":"Pacific Real Estate Academy",
"course":"8-Hour CE: Agency Law 2026",
"recipients":[{"recipient_name":"Jane Martinez"}]}'
The response gives you a certs array with, per recipient:
-
verify_url— the permanent public verification page. Drop it in the completion email, the LMS record, or a QR code on the printed certificate. -
cert_url— a rendered certificate image (SVG) you can attach or embed. -
json_url— the signed record endpoint. It returns the Ed25519signature_b64, the exactcanonicalstring that was signed, and the issuer'spublic_key(base64 / hex /did:key), so anyone can verify the certificate against Attestify's published key without even trusting the web page:ed25519_verify(pubkey, utf8(canonical), base64decode(signature_b64)). -
cert_id— the short id used in all three URLs.
Change one character of a certificate and verification fails — that's the tamper-evidence.
An optional date field (YYYY-MM-DD) sets the completion date; recipient email is never stored
in the signed record or shown publicly.
Wire it into the completion event
The trigger is whatever marks completion in your stack:
-
LMS / form / spreadsheet webhook → call
/cert/issue→ writeverify_urlback to the learner record and the completion email. -
n8n: there's a verified community node,
n8n-nodes-attestify— search "Attestify" in the node browser. One node: completion event in,verify_urlout. -
Cron/batch: loop your completions list and POST one request per recipient (the
recipientsarray also takes multiple names per call).
That's genuinely the whole integration — because verification is public and account-free, there is
no OAuth dance and no recipient onboarding.
When you'd pick something else
Honest map of the space:
- Certifier, Sertifier, Virtualbadge.io, IssueBadge — full credentialing platforms: branded designer templates, LMS integrations, analytics dashboards, badge standards (Open Badges). Pick one if you want a managed white-label program and are ready to pay per credential at scale. Attestify's wedge is the opposite end: free, no account, one HTTP call, and the verify layer is the product.
- W3C Verifiable Credentials / OpenID4VCI — the standards route. Right when you need wallet-based, holder-controlled credentials interoperable across issuers; it's a build, not an API call.
- Plain PDF generators (PDF Generator API, Google Slides templates, HTML→image nodes) — fine for décor, but the output is exactly the editable artifact this post is about replacing. If you keep them, at least pair the PDF with a signed verify URL.
FAQ
Is there an API to create cryptographically verifiable certificates with a public verify page?
Yes — that's the walkthrough above: POST https://attestify.novadyne.ai/cert/issue, free, no
auth; every certificate returns a permanent public verify_url.
How does the recipient's employer verify a certificate? They open the verify_url (or scan
the QR you printed from it). No account, two clicks. The page reads the authoritative server
record, not the image.
What makes it tamper-evident rather than just "hosted"? The Ed25519 signature over the
canonical record. A hosted-but-unsigned certificate page proves only that a page exists; a
signed record proves what was issued and breaks loudly if anything is altered.
Top comments (0)