🎯 What is this guide?
SchoolSuit automatically injects real student data, scores, comments, and school info into your HTML template. Insert {{ student.name }} placeholders, and the system does the rest. No programming skills required — just pick variables from tables below.
✍️ Three simple steps
1️⃣ Download or design
Use our free templates or build HTML with placeholders.
2️⃣ Upload to SchoolSuit
Admin panel → Reports → Templates → upload .html file.
3️⃣ Generate PDF
Select student, term → “Generate Report” → live data injected.
💳 How credits work
⚠️ Each unique report consumes 1 credit.
✔️ Same student + session + term → cached regeneration: 0 credits.
✔️ Check wallet balance in admin panel.
✔️ Bulk generation deducts only for new reports.
📁 Free templates – ready to upload
🎨 Need a custom template?
We design brand‑matched report cards (logo, colors, layout). Starting at $49 one‑time. Email support@cbthost.com or live chat.
🔌 Custom Result Page Integration
You can build your own student result portal on your website using our Public API. This allows parents and students to fetch results directly from your domain, with full control over the design.
⚠️ Important – External printing must be activated
For security and billing reasons, PDF generation via the Public API is only allowed if the school has enabled “Allow External API Printing” in the admin panel. If disabled, calls to /public/student-result-pdf will return a 403 Forbidden. However, you can still fetch raw result data (JSON) and render it yourself without PDF generation.
✅ To enable: Admin → School Settings → Enable Public API Access + Enable Public PDF Generation.
📥 Download ready‑to‑use PHP portal
A complete self‑contained PHP script that fetches sessions/terms and allows students to download their PDF results. Just edit the $SCHOOL_ID and upload to your server.
🌐 API Endpoints (Public)
GET /public/schools/{school_id}/published-sessions
GET /public/student-result?school_id=...&student_reg=...&academic_session_id=...&term_id=...
POST /public/student-result-pdf (JSON body with school_id, student_reg, academic_session_id, term_id)
🐘 PHP Example (cURL)
// 1. Fetch available sessions
$url = "https://your-domain.com/public/schools/YOUR_SCHOOL_ID/published-sessions";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$sessions = json_decode($response, true);
// 2. Get raw result data (JSON)
$params = http_build_query([
'school_id' => 'YOUR_SCHOOL_ID',
'student_reg' => 'STU123',
'academic_session_id' => 10,
'term_id' => 1
]);
$resultUrl = "https://your-domain.com/public/student-result?" . $params;
$resultJson = file_get_contents($resultUrl);
$studentData = json_decode($resultJson, true);
// 3. Download PDF (POST)
$postData = json_encode([
'school_id' => 'YOUR_SCHOOL_ID',
'student_reg' => 'STU123',
'academic_session_id' => 10,
'term_id' => 1
]);
$ch = curl_init("https://your-domain.com/public/student-result-pdf");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$pdf = curl_exec($ch);
header('Content-Type: application/pdf');
echo $pdf;
🐍 Python Example (requests)
import requests
BASE = "https://your-domain.com/public"
SCHOOL_ID = "YOUR_SCHOOL_ID"
# 1. Get sessions
resp = requests.get(f"{BASE}/schools/{SCHOOL_ID}/published-sessions")
sessions = resp.json()
# 2. Get raw result JSON
params = {
"school_id": SCHOOL_ID,
"student_reg": "STU123",
"academic_session_id": 10,
"term_id": 1
}
result = requests.get(f"{BASE}/student-result", params=params)
print(result.json())
# 3. Download PDF
payload = {
"school_id": SCHOOL_ID,
"student_reg": "STU123",
"academic_session_id": 10,
"term_id": 1
}
pdf_response = requests.post(f"{BASE}/student-result-pdf", json=payload)
with open("result.pdf", "wb") as f:
f.write(pdf_response.content)
📋 Variable reference — copy & paste
Most used placeholders. Click copy to grab.
| What you need | Placeholder |
|---|---|
| Student full name | {{ student.name }} |
| Class name | {{ student.class }} |
| Average score | {{ summary.average_score }} |
| Position in class | {{ summary.class_position }} |
| Teacher comment | {{ summary.teacher_comment }} |
| School name | {{ school.name }} |
👤 Student information
| Placeholder | Description |
|---|---|
| {{ student.name }} | Full name |
| {{ student.surname }} | Last name only |
| {{ student.othernames }} | First & middle names |
| {{ student.reg_no }} | Registration number |
| {{ student.class }} | Class name |
| {{ student.gender }} | Gender |
| {{ student.dob }} | Date of birth |
| {{ student.age }} | Age |
| {{ student.passport_photo }} | Photo URL/Base64 |
🏫 School & session
| {{ $v }} | ".explode('.',$v)[1]." | ";} ?>
📊 Academic summary
| {{ summary.$k }} | ".str_replace('_',' ',$k)." | ";} ?>
🧑🏫 Staff / signatures
| {{ staff.form_master }} | Class teacher |
| {{ staff.class_teacher }} | Alternative teacher |
| {{ staff.admin_name }} | Principal name |
🔄 Dynamic subjects & assessment columns
Loop example for full results table. The assessment_fields adapts to your school settings.
<table border="1" cellpadding="6">
<thead>
<th>Subject</th>{% for field in assessment_fields %}<th>{{ field.display_name }}</th>{% endfor %}<th>Total</th><th>Grade</th><th>Remark</th>
</thead>
<tbody>{% for subject in subjects %}
<td>{{ subject.name }}</td>{% for field in assessment_fields %}<td>{{ subject.assessment_scores[field.field_code] }}</td>{% endfor %}
<td>{{ subject.total }}</td><td>{{ subject.grade }}</td><td>{{ subject.remark }}</td>
{% endfor %}
</tbody>
</table>
{{ subject.position }}, {{ subject.code }} and inside assessment_fields: {{ field.max_score }}, {{ field.weight }}.🧠 Psychomotor & affective ratings (1–5 scale)
{% if psychomotor %}
<h4>Psychomotor skills</h4>
<table>
<tr><th>Skill</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th></tr>
{% for skill, rating in psychomotor.items() %}
<tr>
<td>{{ skill }}</td>
{% for i in [1,2,3,4,5] %}<td>{% if rating == i %}✓{% else %}·{% endif %}</td>{% endfor %}
</tr>
{% endfor %}
</table>
{% endif %}
Same for {{ affective }}. Both dictionaries are optional.
📌 Important notes
- Variables are case‑sensitive:
{{ student.name }}works,{{ Student.Name }}fails. - Missing data becomes blank – no errors.
- Always use Preview before setting default template.
- The PDF engine supports modern CSS (Flexbox, Grid, custom fonts).
- Bulk generation uses same template for all students.
Template development: Use normal CSS
For creating report card templates that will be converted to PDF, we strongly recommend using standard, widely‑supported CSS (flex, grid, margins, borders, fonts). Avoid Tailwind CSS, heavy frameworks or complex JavaScript inside the template itself — the PDF renderer works best with plain, robust CSS. However, this guide page is built with Tailwind for convenience; your actual report templates should rely on normal CSS.
style="color: navy; font-size: 14px;" or external stylesheets. Keep it simple for perfect PDF output.