Proof Credential
Issuing 10,000 completion certificates in 8 minutes flat.
EdTech · Seed stage · 5 engineers
The build
Course platform issuing personalized completion certificates per cohort. Went from hand-run 9-hour batch to API-driven 8-minute parallel run.
Stack
- · Rails
- · Postgres
- · Sidekiq
- · Resend
- · SnapPDF
Architecture
Ops used: /fill-form → /metadata → /protect
How they use SnapPDF
Proof Credential runs a cohort-based learning platform for mid-career professionals. Every six weeks, between 2,000 and 10,000 learners complete a program and expect a downloadable, personalized completion certificate with a unique credential ID that a future employer can verify.
The prior process: a part-time contractor at $45/hr ran a mail-merge in InDesign, exported to PDF, uploaded to their platform. A 3,000-person cohort took nine hours. A 10,000-person cohort broke InDesign and required them to chunk it manually.
The SnapPDF version runs as a Sidekiq job. For each graduate: fill the template with name + course + date + credential ID, stamp the credential ID into PDF metadata (so the verification page can read it back), protect with AES-256 to prevent editing. 20 parallel workers. 10,000 graduates → 8 minutes wall-clock.
Cost: ~$948/year (Pro plan) vs ~$16,200/year in contractor fees. The saving is only part of the win — graduates now receive their certificate within minutes of finishing the final module, not days. NPS jumped 12 points; the support team spent 70% less time on "where's my certificate" tickets.
The verification page is where metadata pays off. When a hiring manager uploads a candidate's certificate to Proof's verify page, the page reads the credential ID from PDF metadata, looks it up, displays "ISSUED 2026-04-12 · Valid" with the course details. No OCR, no QR-code scanning — the identifier is in the file itself.
Outcomes
Integration pattern
A simplified excerpt showing the core SnapPDF calls.
# app/jobs/issue_certificates_job.rb
class IssueCertificatesJob < ApplicationJob
queue_as :certificates
def perform(cohort_id)
cohort = Cohort.find(cohort_id)
snap = SnapPDF::Client.new(api_key: ENV['SNAPPDF_KEY'])
cohort.graduates.find_each(batch_size: 100) do |grad|
filled = snap.pdf.fill_form(
file: cohort.template_url,
values: {
student_name: grad.display_name,
course_title: cohort.program.title,
completion_date: Date.today.iso8601,
credential_id: grad.credential_id,
},
flatten: true
)
tagged = snap.pdf.set_metadata(
file: filled.pdf,
metadata: {
title: "#{cohort.program.title} Certificate",
subject: grad.credential_id,
keywords: ['certificate', cohort.program.slug, grad.credential_id],
}
)
locked = snap.pdf.protect(
file: tagged.pdf,
owner_password: Rails.application.credentials.cert_vault_key,
encryption: 'aes-256'
)
CertMailer.with(graduate: grad, pdf: locked.pdf).issued.deliver_later
grad.update!(certificate_issued_at: Time.current)
end
end
endStart building like this
Free tier gives you 100 ops/month — enough to prototype any of the flows on this page. No card required.