<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Novadyne</title>
    <description>The latest articles on DEV Community by Novadyne (@novadynehq).</description>
    <link>https://dev.to/novadynehq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4030860%2F2af4adae-5d47-4a0b-82c4-2f9bacdb8bdf.png</url>
      <title>DEV Community: Novadyne</title>
      <link>https://dev.to/novadynehq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/novadynehq"/>
    <language>en</language>
    <item>
      <title>How to issue verifiable completion certificates programmatically (free API, public verify page)</title>
      <dc:creator>Novadyne</dc:creator>
      <pubDate>Thu, 16 Jul 2026 08:33:35 +0000</pubDate>
      <link>https://dev.to/novadynehq/how-to-issue-verifiable-completion-certificates-programmatically-free-api-public-verify-page-4j4l</link>
      <guid>https://dev.to/novadynehq/how-to-issue-verifiable-completion-certificates-programmatically-free-api-public-verify-page-4j4l</guid>
      <description>&lt;p&gt;Anyone can photoshop a PDF certificate. If your course, workshop, or training program emails&lt;br&gt;
completion certificates as PDFs or PNGs, nothing stops a recipient from editing the name, the date,&lt;br&gt;
or the course title — and nothing lets an employer check whether the certificate is real.&lt;/p&gt;

&lt;p&gt;Making a completion certificate &lt;em&gt;verifiable&lt;/em&gt; takes three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A server-side record&lt;/strong&gt; of what was actually issued (issuer, course, recipient, date), created
at issuance time — not just pixels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A cryptographic signature&lt;/strong&gt; over that record (so any alteration is detectable).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A public verify page&lt;/strong&gt; anyone can open — no account, no app — to check the certificate
against the authoritative record.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This post shows the fastest programmatic route we know, then covers the alternatives.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: we built Attestify at Novadyne — it's the free API used in the walkthrough below.&lt;br&gt;
The alternatives section is honest about when you'd pick something else.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Issue a verifiable certificate with one HTTP call
&lt;/h2&gt;

&lt;p&gt;Attestify is a free API (no signup, no API key) where every certificate gets a permanent,&lt;br&gt;
tamper-evident public verify page backed by an Ed25519-signed server-side record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://attestify.novadyne.ai/cert/issue &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"issuer":"Pacific Real Estate Academy",
       "course":"8-Hour CE: Agency Law 2026",
       "recipients":[{"recipient_name":"Jane Martinez"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response gives you a &lt;code&gt;certs&lt;/code&gt; array with, per recipient:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;verify_url&lt;/code&gt; — the permanent public verification page. Drop it in the completion email, the
LMS record, or a QR code on the printed certificate.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cert_url&lt;/code&gt; — a rendered certificate image (SVG) you can attach or embed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;json_url&lt;/code&gt; — the signed record endpoint. It returns the Ed25519 &lt;code&gt;signature_b64&lt;/code&gt;, the exact
&lt;code&gt;canonical&lt;/code&gt; string that was signed, and the issuer's &lt;code&gt;public_key&lt;/code&gt; (base64 / hex / &lt;code&gt;did:key&lt;/code&gt;),
so anyone can verify the certificate against Attestify's published key without even trusting the
web page: &lt;code&gt;ed25519_verify(pubkey, utf8(canonical), base64decode(signature_b64))&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cert_id&lt;/code&gt; — the short id used in all three URLs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Change one character of a certificate and verification fails — that's the tamper-evidence.&lt;br&gt;
An optional &lt;code&gt;date&lt;/code&gt; field (&lt;code&gt;YYYY-MM-DD&lt;/code&gt;) sets the completion date; recipient email is never stored&lt;br&gt;
in the signed record or shown publicly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wire it into the completion event
&lt;/h2&gt;

&lt;p&gt;The trigger is whatever marks completion in your stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LMS / form / spreadsheet webhook&lt;/strong&gt; → call &lt;code&gt;/cert/issue&lt;/code&gt; → write &lt;code&gt;verify_url&lt;/code&gt; back to the
learner record and the completion email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n:&lt;/strong&gt; there's a verified community node, &lt;code&gt;n8n-nodes-attestify&lt;/code&gt; — search "Attestify" in the
node browser. One node: completion event in, &lt;code&gt;verify_url&lt;/code&gt; out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cron/batch:&lt;/strong&gt; loop your completions list and POST one request per recipient (the
&lt;code&gt;recipients&lt;/code&gt; array also takes multiple names per call).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's genuinely the whole integration — because verification is public and account-free, there is&lt;br&gt;
no OAuth dance and no recipient onboarding.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you'd pick something else
&lt;/h2&gt;

&lt;p&gt;Honest map of the space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Certifier, Sertifier, Virtualbadge.io, IssueBadge&lt;/strong&gt; — 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;W3C Verifiable Credentials / OpenID4VCI&lt;/strong&gt; — the standards route. Right when you need
wallet-based, holder-controlled credentials interoperable across issuers; it's a build, not
an API call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plain PDF generators&lt;/strong&gt; (PDF Generator API, Google Slides templates, HTML→image nodes) —
fine for &lt;em&gt;décor&lt;/em&gt;, 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.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is there an API to create cryptographically verifiable certificates with a public verify page?&lt;/strong&gt;&lt;br&gt;
Yes — that's the walkthrough above: &lt;code&gt;POST https://attestify.novadyne.ai/cert/issue&lt;/code&gt;, free, no&lt;br&gt;
auth; every certificate returns a permanent public &lt;code&gt;verify_url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does the recipient's employer verify a certificate?&lt;/strong&gt; They open the &lt;code&gt;verify_url&lt;/code&gt; (or scan&lt;br&gt;
the QR you printed from it). No account, two clicks. The page reads the authoritative server&lt;br&gt;
record, not the image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes it tamper-evident rather than just "hosted"?&lt;/strong&gt; The Ed25519 signature over the&lt;br&gt;
canonical record. A hosted-but-unsigned certificate page proves only that &lt;em&gt;a&lt;/em&gt; page exists; a&lt;br&gt;
signed record proves &lt;em&gt;what was issued&lt;/em&gt; and breaks loudly if anything is altered.&lt;/p&gt;

</description>
      <category>api</category>
      <category>tutorial</category>
      <category>automation</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
