API v1 · Terakhir diperbarui: Februari 2026
Integrasikan platform ujian online Pinaga dengan sistem Anda. Enterprise API mendukung manajemen siswa, ujian, hasil, analitik, dan webhook secara programatis melalui RESTful endpoints.
Import ke Postman dan langsung coba semua 20 endpoint — sudah lengkap dengan contoh request & variabel.
Enterprise API memungkinkan Anda mengotomasi dan mengintegrasikan platform Pinaga dengan sistem informasi sekolah (SIS), Learning Management System (LMS), atau aplikasi custom Anda. Semua endpoint menggunakan format JSON dan memerlukan autentikasi Bearer Token.
CRUD siswa, import bulk, sinkronisasi SIS
Kelola ujian, soal, publish/unpublish
Ambil hasil ujian, statistik performa
Event-driven notifikasi real-time
Semua request ke Enterprise API harus menyertakan API key di header Authorization. API key bisa dibuat melalui halaman Pengaturan > API di workspace admin.
Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/jsoncurl -X GET "https://yourtenant.pinaga.id/api/v1/enterprise/students" \
-H "Authorization: Bearer pk_live_your_secret_key_here" \
-H "Content-Type: application/json"Base URL mengikuti domain tenant Anda. Jika menggunakan custom domain, gunakan domain tersebut.
# Subdomain
https://{tenant}.pinaga.id/api/v1/enterprise
# Custom Domain
https://ujian.sekolahanda.sch.id/api/v1/enterprise
# Development
http://localhost:3000/api/v1/enterpriseRate limit diterapkan per API key berdasarkan tier langganan Anda:
| Tier | Per Menit | Per Jam | Per Hari | Per Bulan |
|---|---|---|---|---|
| Default | 100 | 1.000 | 10.000 | 100.000 |
| Pro | 500 | 5.000 | 50.000 | 500.000 |
| Enterprise | 1.000 | 10.000 | 100.000 | 1.000.000 |
Response header menampilkan info quota Anda:
X-Quota-Used: 1523
X-Quota-Limit: 100000
X-Quota-Remaining: 98477Semua response menggunakan format JSON yang konsisten:
{
"success": true,
"data": { ... },
"pagination": {
"current_page": 1,
"total_pages": 5,
"total_count": 48,
"per_page": 10,
"has_next": true,
"has_prev": false
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-02-19T10:30:00.000Z"
}
}{
"success": false,
"error": "Student not found",
"code": "NOT_FOUND"
}Pagination didukung melalui query parameter:
?page=1 # halaman (default: 1)
&limit=10 # jumlah per halaman (default: 10, max: 100)
&sort=name # field untuk sorting
&order=asc # asc atau descSetiap API key memiliki scope spesifik yang membatasi akses. Pilih scope minimal yang dibutuhkan (principle of least privilege).
| Scope | Deskripsi | Akses |
|---|---|---|
students:read | Membaca data siswa | GET students |
students:write | Membuat/memperbarui data siswa | POST/PUT students |
students:delete | Menghapus data siswa | DELETE students |
exams:read | Membaca data ujian | GET exams |
exams:write | Membuat/memperbarui ujian | POST/PUT exams |
exams:publish | Publish/unpublish ujian | POST publish/unpublish |
results:read | Membaca hasil ujian | GET results |
analytics:read | Mengakses data analitik | GET analytics |
webhooks:manage | Mengelola webhook endpoints | CRUD webhooks |
Kelola data siswa dalam tenant Anda. Mendukung CRUD individual dan bulk import.
/api/v1/enterprise/studentsstudents:readMengambil daftar siswa dengan paginasi, filter, dan sorting.
?search=budi # Cari berdasarkan nama/email
&category=kelas-10 # Filter berdasarkan kategori
&include=categories,stats # Sertakan data relasi
&sort=name&order=asc # Sorting
&page=1&limit=20 # Paginasi{
"success": true,
"data": [
{
"id": "uuid",
"name": "Budi Santoso",
"email": "budi@sekolah.sch.id",
"student_id": "10A-001",
"student_code": "STD001",
"category": "Kelas 10A",
"created_at": "2026-01-15T08:00:00Z",
"stats": {
"total_exams": 12,
"avg_score": 85.5,
"completed_exams": 10
}
}
],
"pagination": { "current_page": 1, "total_count": 150, ... }
}/api/v1/enterprise/studentsstudents:writeMembuat siswa baru. Email harus unik dalam tenant.
{
"name": "Budi Santoso",
"email": "budi@sekolah.sch.id",
"student_id": "10A-001",
"student_code": "STD001",
"category_id": "uuid-kategori"
}/api/v1/enterprise/students/:idstudents:readMengambil detail siswa beserta kategori dan statistik.
/api/v1/enterprise/students/:idstudents:writeMemperbarui data siswa (name, email, student_id, student_code, category).
/api/v1/enterprise/students/:id/passwordstudents:writeMenetapkan atau mereset password login siswa. Password tidak pernah dikembalikan pada respons.
{
"password": "PasswordBaru123!"
}Password harus 12–128 karakter serta mengandung huruf besar, huruf kecil, dan angka.
{
"success": true,
"data": {
"id": "uuid",
"password_updated": true
}
}/api/v1/enterprise/students/:idstudents:deleteMenghapus siswa secara permanen.
/api/v1/enterprise/students/bulkstudents:writeBulk import hingga 500 siswa. Mendukung mode skip_duplicates dan upsert.
{
"students": [
{ "name": "Budi Santoso", "email": "budi@sekolah.sch.id", "student_id": "10A-001" },
{ "name": "Siti Nurhaliza", "email": "siti@sekolah.sch.id", "student_id": "10A-002" }
],
"options": {
"on_conflict": "skip_duplicates",
"category_id": "uuid-kategori"
}
}{
"success": true,
"data": {
"created": 45,
"skipped": 3,
"updated": 0,
"errors": []
}
}Kelola ujian: buat, update, publish/unpublish secara programatis.
/api/v1/enterprise/examsexams:readMengambil daftar ujian dengan filter status, tanggal, pencarian, dan paginasi.
?status=published # draft, published, archived
&search=matematika # Cari berdasarkan judul
&from=2026-01-01 # Filter tanggal mulai
&to=2026-02-28 # Filter tanggal selesai
&include=stats # Sertakan statistik
&page=1&limit=10/api/v1/enterprise/examsexams:writeMembuat ujian baru. Bisa menyertakan soal inline.
{
"title": "Ujian Tengah Semester Matematika",
"description": "UTS Matematika Kelas 10",
"duration": 90,
"settings": {
"shuffle_questions": true,
"shuffle_options": true,
"show_score_immediately": false
},
"schedule": {
"start_time": "2026-03-01T08:00:00Z",
"end_time": "2026-03-01T10:00:00Z"
},
"questions": [
{
"type": "multiple_choice",
"text": "Berapakah 2 + 2?",
"options": ["3", "4", "5", "6"],
"correct_answer": 1,
"points": 10
}
]
}/api/v1/enterprise/exams/:idexams:readMengambil detail ujian. Gunakan ?include=questions untuk menyertakan soal.
/api/v1/enterprise/exams/:idexams:writeMemperbarui ujian (title, description, duration, settings, schedule).
/api/v1/enterprise/exams/:idexams:writeMenghapus ujian beserta semua soalnya.
/api/v1/enterprise/exams/:id/publishexams:publishMempublikasikan ujian (harus memiliki minimal 1 soal).
/api/v1/enterprise/exams/:id/unpublishexams:publishMembatalkan publikasi ujian (kembali ke draft).
Ambil hasil pengerjaan ujian siswa dengan filter dan analitik.
/api/v1/enterprise/exams/:id/resultsresults:readMengambil hasil ujian tertentu. Filter berdasarkan skor, status, atau tanggal.
?min_score=60 # Skor minimum
&max_score=100 # Skor maksimum
&status=completed # completed, in_progress
&from=2026-01-01 # Filter tanggal
&include=analytics # Sertakan analitik ujian
&page=1&limit=20{
"success": true,
"data": {
"results": [
{
"student": {
"id": "uuid",
"name": "Budi Santoso",
"email": "budi@sekolah.sch.id"
},
"score": 85,
"max_score": 100,
"percentage": 85.0,
"status": "completed",
"started_at": "2026-02-19T08:00:00Z",
"completed_at": "2026-02-19T09:15:00Z",
"time_spent_seconds": 4500
}
],
"analytics": {
"avg_score": 72.5,
"median_score": 75,
"highest_score": 98,
"lowest_score": 35,
"completion_rate": 94.2,
"total_participants": 48
}
}
}Akses analitik tenant-wide: overview, performa, dan penggunaan API.
/api/v1/enterprise/analyticsanalytics:readAnalitik keseluruhan tenant dengan periode yang bisa disesuaikan.
?period=30d # 7d, 30d, 90d, 1y{
"success": true,
"data": {
"overview": {
"total_students": 520,
"total_exams": 45,
"total_submissions": 2340,
"active_exams": 8
},
"performance": {
"avg_score": 74.2,
"completion_rate": 91.5,
"top_exam": "UTS Matematika Kelas 10"
},
"api_usage": {
"total_requests": 15230,
"success_rate": 99.2,
"avg_response_time_ms": 145
}
}
}Terima notifikasi real-time saat event terjadi di platform Pinaga. Webhook mengirim POST request ke URL Anda dengan payload JSON yang ditandatangani menggunakan HMAC-SHA256.
| Event | Deskripsi |
|---|---|
exam.created | Ujian baru dibuat |
exam.updated | Ujian diperbarui |
exam.published | Ujian dipublikasikan |
exam.unpublished | Publikasi ujian dibatalkan |
exam.deleted | Ujian dihapus |
exam.completed | Semua siswa selesai mengerjakan |
student.created | Siswa baru ditambahkan |
student.updated | Data siswa diperbarui |
student.deleted | Siswa dihapus |
student.enrolled | Siswa didaftarkan ke ujian |
result.graded | Hasil ujian dinilai |
result.released | Hasil ujian dirilis ke siswa |
/api/v1/enterprise/webhookswebhooks:manageMengambil daftar webhook (secrets di-mask).
/api/v1/enterprise/webhookswebhooks:manageMembuat webhook baru (max 10 per tenant). Secret otomatis di-generate. URL harus HTTPS di production.
{
"url": "https://yourapp.com/webhooks/pinaga",
"events": ["exam.published", "result.graded", "student.created"],
"max_retries": 3,
"retry_delay_seconds": 60
}/api/v1/enterprise/webhooks/:idwebhooks:manageDetail webhook. Gunakan ?include=deliveries untuk melihat log pengiriman.
/api/v1/enterprise/webhooks/:idwebhooks:manageUpdate webhook (url, events, active status, retry config).
/api/v1/enterprise/webhooks/:idwebhooks:manageHapus webhook dan semua log pengirimannya.
Setiap webhook request menyertakan header X-Pinaga-Signature berisi HMAC-SHA256 dari payload. Selalu verifikasi signature untuk keamanan.
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Di webhook handler Anda:
app.post('/webhooks/pinaga', (req, res) => {
const signature = req.headers['x-pinaga-signature'];
if (!verifyWebhook(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Proses event
const { event, data, timestamp } = req.body;
console.log(`Event: ${event}`, data);
res.status(200).json({ received: true });
});{
"event": "exam.published",
"data": {
"id": "uuid",
"title": "UTS Matematika",
"status": "published",
"published_at": "2026-02-19T10:00:00Z"
},
"timestamp": "2026-02-19T10:00:01Z",
"webhook_id": "uuid",
"delivery_id": "uuid"
}API menggunakan HTTP status code standar dan menyertakan kode error spesifik:
| HTTP | Code | Deskripsi |
|---|---|---|
| 400 | BAD_REQUEST | Payload/parameter tidak valid |
| 401 | UNAUTHORIZED | API key tidak valid atau expired |
| 403 | FORBIDDEN | Scope tidak mencukupi / IP tidak diizinkan |
| 404 | NOT_FOUND | Resource tidak ditemukan |
| 409 | CONFLICT | Duplikat data (misal email sudah ada) |
| 422 | VALIDATION_ERROR | Validasi input gagal |
| 429 | RATE_LIMITED | Melebihi batas rate limit |
| 500 | INTERNAL_ERROR | Server error (hubungi support) |
Contoh integrasi dalam berbagai bahasa pemrograman:
const PINAGA_API_KEY = process.env.PINAGA_API_KEY;
const BASE_URL = 'https://yourtenant.pinaga.id/api/v1/enterprise';
// List semua siswa
async function getStudents(page = 1) {
const res = await fetch(`${BASE_URL}/students?page=${page}&limit=50`, {
headers: {
'Authorization': `Bearer ${PINAGA_API_KEY}`,
'Content-Type': 'application/json',
},
});
if (!res.ok) {
const err = await res.json();
throw new Error(`API Error: ${err.error} (${err.code})`);
}
return res.json();
}
// Buat siswa baru
async function createStudent(data) {
const res = await fetch(`${BASE_URL}/students`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${PINAGA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
return res.json();
}
// Contoh penggunaan
const result = await getStudents();
console.log(`Total: ${result.pagination.total_count} siswa`);import requests
import os
API_KEY = os.environ['PINAGA_API_KEY']
BASE_URL = 'https://yourtenant.pinaga.id/api/v1/enterprise'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json',
}
# List siswa
response = requests.get(f'{BASE_URL}/students', headers=headers)
data = response.json()
print(f"Total: {data['pagination']['total_count']} siswa")
# Bulk import
students = [
{"name": "Budi", "email": "budi@sekolah.id", "student_id": "10A-001"},
{"name": "Siti", "email": "siti@sekolah.id", "student_id": "10A-002"},
]
response = requests.post(
f'{BASE_URL}/students/bulk',
headers=headers,
json={"students": students, "options": {"on_conflict": "skip_duplicates"}}
)
print(response.json())<?php
$apiKey = getenv('PINAGA_API_KEY');
$baseUrl = 'https://yourtenant.pinaga.id/api/v1/enterprise';
function pinagaRequest($method, $endpoint, $data = null) {
global $apiKey, $baseUrl;
$ch = curl_init($baseUrl . $endpoint);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $apiKey",
"Content-Type: application/json",
],
CURLOPT_CUSTOMREQUEST => $method,
]);
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// List ujian
$exams = pinagaRequest('GET', '/exams?status=published');
echo "Ujian published: " . count($exams['data']);
// Ambil hasil ujian
$results = pinagaRequest('GET', '/exams/' . $examId . '/results');
?>Jika mengalami kendala atau memiliki pertanyaan tentang Enterprise API, silakan hubungi tim support kami.