Table of Contents
- Overview
- Authentication
- Base URL
- Endpoints
- 1. Get Certified Trainings by Student
- 2. Get Certified Exams by Student
- 3. Get Certified Students by Training
- 4. Get Certified Students by Exam
- 5. Get Certifications by User
- 6. Create Certification
- 7. Get Certification Details
- 8. Get Global Certification Config
- 9. Set Global Certification Config
- 10. Generate Certification Handler URL
- 11. Verify Certification
- 12. View Certificate Handler (Web Page)
- 12b. Certificate Preview Image (PNG)
- 13. View Certification Verification Page
- 14. Render Certificate from JSON
- Postman Setup
- Certificate Payload Reference
- Error Handling
Overview
The Certifications API allows you to create, view, verify, and configure training and exam completion certificates. The current flow is based on a public certificate handler URL:- A certification is created through
POST /api/certification - The API generates a unique public
certification_id - A public handler URL is returned, such as
/certificate/ID/CERT-TR00012-20260413-00004 - The certificate page uses the
resources/views/certificate.blade.phpBlade file
- Quiz-based certifications are now exam-only
- Each student can have only one certification per training and one certification per exam
POST /api/certificationis idempotent for the samestudent_id + training_idorstudent_id + quiz_id- If the certification already exists, the API returns the existing certification instead of creating a new one, with
already_exists: trueand a message saying that nothing new was generated - A certification is issued once and is never regenerated, even when lessons or quizzes are added to the training afterwards
- Listing endpoints return duplicate-safe results
- Listing endpoints load each certification’s
trainingwith itsbadge_logofile and eachquizwith itsimage, so a client can draw the badge of a certificate without a second request GET /api/certification/{id}now returns certification data instead of downloading a PDF- Archive, old preview URL, and old preview query-page flows are no longer part of the active certification flow
- The certificate payload now includes:
namecoursedatedurationduration_labelsubject_labelsignatorycompany_logobadge_logocertification_id
Authentication
Authenticated API endpoints require a Bearer Token via Laravel Sanctum:POST /api/auth/login.
Public endpoints in the current certification flow:
POST /api/certification/handler-urlPOST /api/certification/verifyGET /certificate/ID/{certification_id}GET /certificate/verifyGET /certificate
Base URL
/api prefix:
Endpoints
1. Get Certified Trainings by Student
Returns all training-based certifications for a given student. The response is duplicate-safe: only one certification per student per training is returned. Eachtraining comes with its badge_logo file (null when the training has no badge of its own; clients then fall back to the company’s default_badge_logo, endpoint 8).
Example Request
200 OK
2. Get Certified Exams by Student
Returns all exam-based certifications for a given student. Current supported URLs:- Preferred:
/api/certified_exams_by_student/{student_id} - Backward-compatible alias:
/api/certified_quizzes_by_student/{student_id}
Example Request
200 OK
3. Get Certified Students by Training
Returns all certifications issued for a specific training. The response is duplicate-safe: only one certification per student for that training is returned.
Example Request
200 OK
4. Get Certified Students by Exam
Returns all certifications issued for a specific exam. Current supported URLs:- Preferred:
/api/certified_students_by_exam/{quiz_id} - Backward-compatible alias:
/api/certified_students_by_quiz/{quiz_id}
Example Request
200 OK
5. Get Certifications by User
Returns all certifications belonging to a specific user, without separating training certifications from exam certifications. You may search by:user_iduser_email
training(training certifications): the training row with itsbadge_logofile.badge_logoisnullwhen the training has no badge of its own; the client then falls back to the company’sdefault_badge_logo(endpoint 8). This is the badge the Flutter Certificates tab draws on each earned certificate.quiz(exam certifications): the exam row with itsimagefile.certification_source:trainingorexam.certification_handler_url: the public certificate page.
Example Request by ID
200 OK
training and quiz objects are the full model rows (the samples above are shortened). A training whose badge_logo_id is set but whose badge_logo is null has an archived or deleted badge file.
6. Create Certification
Creates a new certification for a student and sends an in-app notification when the certification is newly created. This endpoint is idempotent for the certification target:- Repeating the same
student_id + training_idrequest returns the existing training certification - Repeating the same
student_id + quiz_idrequest returns the existing exam certification - No second certification is created for the same student and target
student_id + training_id and student_id + quiz_id) guarantee it even under concurrent requests.
Both outcomes answer 200 OK. Use the already_exists flag to tell them apart instead of parsing message:
The status is deliberately not
409: the goal of the request (the student holds a certification) is met, and the client needs the body to display it.
Message when the certification already exists
This message is translated from the
Accept-Language header (en, fr, ar; any other value falls back to en). The “created” message is always in English.
You must send exactly one of:
training_idquiz_id
quiz_id is used, it must point to an exam only.
Example Request
Success Response —
200 OK
200 OK
Returned for every repeat request, including after the training content has changed.
422 Unprocessable Entity
7. Get Certification Details
Returns certification data, the public certificate handler URL, and the certificate payload used by the Blade handler. This endpoint no longer downloads a PDF.
Example Request
200 OK
8. Get Global Certification Config
Retrieves the company-level certification display configuration used by the certificate payload builder.
Example Request
200 OK
200 OK
default_badge_logoreturns the public URL of the custom badge image uploaded via endpoint 9. When no value is saved for the company, it falls back to the platform default badge. The same resolution is used as the fallbackbadge_logoin the certificate payload when a training/exam has no badge of its own.
certificate_verify_urlis where the app sends “Verify your certificate”. Like everycertification_handler_url, it is built on the backend’sCERTIFICATE_PUBLIC_URLwhen that is set — the app’s own domain, whose web server proxies/certificate/*to the backend, so shared links never show the backend host (seeCertification_Proxy_README.mdin the backend and frontend repositories) — and onAPP_URLotherwise.
9. Set Global Certification Config
Updates the company-level certification configuration. Only the fields below are currently used by the active handler flow.
Form Data Parameters
default_badge_logo is an image upload (same as the other logos). Upload an image file and its public URL is stored and returned. Sending it empty clears the stored value back to the platform default; omitting it entirely leaves the current value unchanged. This value becomes the fallback badge in the certificate payload when a training/exam has no badge of its own.
Postman Setup
- Set method to
POST - Set body type to
form-data - Add
company_logoasFilewhen uploading a logo - Add
signatoryasTextwhen changing the signer label - Add
default_badge_logoasFileto upload a custom default badge
200 OK
10. Generate Certification Handler URL
Generates the public certificate handler URL from an existing certification. You may send either:idcertification_id
Request Body
200 OK
11. Verify Certification
Verifies a certification by publiccertification_id.
This endpoint is public and does not require authentication.
Request Body
200 OK
404 Not Found
12. View Certificate Handler (Web Page)
Renders the public certificate page usingresources/views/certificate.blade.php.
Example Request
200 OK
The page renders a certificate with:
- student full name
- training label or exam label
- duration
- certification date
- signatory
- company logo
- training badge logo or fallback badge
- generated certification ID
- copy certification ID button
@media print) sets @page { size: A4 landscape; margin: 0 }, hides the .no-print chrome (the action buttons and the details card) and makes the canvas container full-bleed, so the 1123×794 canvas (A4 ratio) prints edge-to-edge on a single sheet with object-fit: contain — no browser margins, no blank second page. On screens narrower than 1024px the certificate is shown above the details card.
Link preview tags
The page’s <head> carries Open Graph and Twitter Card tags, so a shared link previews as the certificate on LinkedIn, Facebook, X, WhatsApp or Slack. Link crawlers do not run the page’s canvas script, so the preview image is a server-drawn PNG (endpoint 12b). Every URL is built on CERTIFICATE_PUBLIC_URL when it is set, else on APP_URL.
og:image is the training badge and twitter:card is summary.
Error Response — 404 Not Found
If the certification identifier does not exist, Laravel returns the standard not found response/page.
12b. Certificate Preview Image (PNG)
The certificate drawn server-side as a 1200×630 PNG: theog:image / twitter:image of endpoint 12. Same layout as the page’s canvas (logo, badge, name, course, duration, date, signatory, certification ID).
Example Request
- Drawn on the first request and cached on the server. The
?v=that endpoint 12 appends is a fingerprint of the drawn content: it changes when the training, the learner’s name, the badge or the signatory change, so social networks fetch the new image. The image itself ignores the query string. - Under
/certificate/, so the app-domain proxy described inCertification_Proxy_README.mdserves it too.
404 Not Found
The certification identifier does not exist, or its texts use a right-to-left script the image cannot render.
13. View Certification Verification Page
Renders the public certification verification page usingresources/views/certificate_verify.blade.php.
Example Request
200 OK
The page lets users:
- enter a public
certification_id - click Verify Certif
- see a success or failure message
- render the certificate inline when verification succeeds
- view the duration and certification ID in the rendered certificate
14. Render Certificate from JSON
Renders the certificate view using the local development JSON file atstorage/app/certificate_data.json.
This route is intended for local testing of the Blade view and requires no authentication.
Example Request
200 OK
The page renders the same Blade used by the public certification handler.
Error Response — 404 Not Found
Postman Setup
Step 1 — Environment Variables
Create a Postman environment with:Step 2 — Login & Save Token
Create aPOST {{base_url}}/auth/login request:
Step 3 — Set Auth Header
For authenticated certification endpoints:- Go to Authorization
- Type: Bearer Token
- Token:
{{token}}
POST {{base_url}}/certification/handler-urlPOST {{base_url}}/certification/verifyGET {{web_url}}/certificate/ID/{certification_id}GET {{web_url}}/certificate/verifyGET {{web_url}}/certificate
Step 4 — Postman Collection Structure
Tips for Testing
- Create Certification: Copy
certification_handler_urlfrom the API response and open it in a browser - Duplicate Protection: Repeating the same create request for the same student and training/exam returns the existing certification instead of creating a new one
- Unified User Lookup: Use
/certifications/by-userwhen you want all certifications for a learner, regardless of source - Verify Certification: Use
/certification/verifyfrom the public verification page or from Postman without auth - Handler URL Endpoint: Useful when you already know the certification database
idor publiccertification_id - Config Uploads: Use
form-dataand setcompany_logoasFile - Exam Certifications: Always use an exam
quiz_id, not a training/chapter quiz
Certificate Payload Reference
The public certificate handler and the local render route both use the following payload structure:GET /certificate reads from:
Image URLs are converted server-side to base64 data URLs when rendering the Blade, to avoid browser-side CORS issues.
Error Handling
All endpoints follow a consistent error format:
Standard error shape
errors object is only present for validation failures.