CPD QC — Quality Certification
For providers

CPDQC API

Connect your learning platform so learners get their CPDQC certificate the moment they complete an accredited course — no spreadsheets.

1. Get a key

Approved members create keys in Dashboard → API. A key is shown once; keep it on your server, never in a browser or app. Send it on every request:

Authorization: Bearer cpdqc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Base URL https://cpdqc.com/api/v1 · JSON in and out · 300 requests a minute per key · 2,000 certificates a day per provider.

2. Issue a certificate when a learner completes

course is your course’s CPDQC id or accreditation number. Pass your own external_id (for example your enrolment id) and retries are safe: the same id always returns the same certificate.

curl -X POST https://cpdqc.com/api/v1/certificates \
  -H "Authorization: Bearer $CPDQC_KEY" -H "Content-Type: application/json" \
  -d '{
    "course": "CPDQC-C-00012",
    "learner_name": "Maya Okafor",
    "learner_email": "[email protected]",
    "completed_on": "2026-10-20",
    "external_id": "enrolment-48213"
  }'
201 Created   (200 if this external_id was already issued)
{
  "result": "issued",            // or "exists" | "duplicate"
  "certificate": {
    "code": "CPDQC-CT-7KQ4-M9XD",
    "url": "https://cpdqc.com/certificates/CPDQC-CT-7KQ4-M9XD",
    "status": "valid", "learner_name": "Maya Okafor", "cpd_points": 4, ...
  }
}

The learner is emailed their certificate (add ?send_email=false to skip that), and it joins their CPDQC record when their email is confirmed. Show certificate.url or the code on your own certificate so anyone can verify it.

Endpoints

GET/providerYour membership, provider number and package usage
GET/coursesYour courses (all statuses), with listings. ?status=approved
GET/courses/{id or CPDQC-C number}One course
POST/coursesCreate a draft course (same fields as the dashboard)
PUT/courses/{ref}Update a course
POST/courses/{ref}/listingsAdd a link where the course is sold — { "url": "…" }
DELETE/courses/{ref}/listings/{listing_id}Remove a link
POST/courses/{ref}/submitSubmit a draft for accreditation (needs a package slot)
POST/certificatesIssue one certificate (safe to retry with external_id)
POST/certificates/batchIssue up to 500 certificates in one call
GET/certificatesYour certificates. ?external_id= ?email= ?course= ?status=
GET/certificates/{code}One certificate
POST/certificates/{code}/revokeRevoke — { "reason": "…" }

Errors

Errors return {"detail": "…"} with a plain-English message: 401 missing/revoked key · 403 membership not approved · 404 not yours / not found · 409 conflict (e.g. course not accredited, link already used) · 422 invalid data · 429 slow down / daily limit. A batch never fails as a whole — each row comes back as issued, exists, duplicate or invalid with a reason.

Links are checked daily

We check every listed course link once a day. A link that fails several days running is hidden from the catalogue and we email you; it reappears as soon as it loads again. Tracking parameters (utm_…, gclid, fbclid) are removed when a link is added, and the same link can’t be listed on two courses.