Kembali

Enterprise API Documentation

API v1 · Terakhir diperbarui: Februari 2026

Pinaga Enterprise API

Integrasikan platform ujian online Pinaga dengan sistem Anda. Enterprise API mendukung manajemen siswa, ujian, hasil, analitik, dan webhook secara programatis melalui RESTful endpoints.

Bearer Token Auth RESTful JSON Webhook Events Scope-based Access
Download Postman Collection

Import ke Postman dan langsung coba semua 20 endpoint — sudah lengkap dengan contoh request & variabel.

Overview

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.

Students API

CRUD siswa, import bulk, sinkronisasi SIS

Exams API

Kelola ujian, soal, publish/unpublish

Results & Analytics

Ambil hasil ujian, statistik performa

Webhooks

Event-driven notifikasi real-time

Autentikasi

Semua request ke Enterprise API harus menyertakan API key di header Authorization. API key bisa dibuat melalui halaman Pengaturan > API di workspace admin.

Request Headerhttp
Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
Simpan API key dengan aman! Secret key hanya ditampilkan sekali saat dibuat. Jangan sertakan API key di kode client-side atau repository publik. Gunakan environment variables.
Contoh cURLbash
curl -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

Base URL mengikuti domain tenant Anda. Jika menggunakan custom domain, gunakan domain tersebut.

Base URLtext
# Subdomain
https://{tenant}.pinaga.id/api/v1/enterprise

# Custom Domain
https://ujian.sekolahanda.sch.id/api/v1/enterprise

# Development
http://localhost:3000/api/v1/enterprise

Rate Limits

Rate limit diterapkan per API key berdasarkan tier langganan Anda:

TierPer MenitPer JamPer HariPer Bulan
Default1001.00010.000100.000
Pro5005.00050.000500.000
Enterprise1.00010.000100.0001.000.000

Response header menampilkan info quota Anda:

Rate Limit Headershttp
X-Quota-Used: 1523
X-Quota-Limit: 100000
X-Quota-Remaining: 98477

Format Response

Semua response menggunakan format JSON yang konsisten:

Success Responsejson
{
  "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"
  }
}
Error Responsejson
{
  "success": false,
  "error": "Student not found",
  "code": "NOT_FOUND"
}

Pagination didukung melalui query parameter:

Pagination Parameterstext
?page=1        # halaman (default: 1)
&limit=10      # jumlah per halaman (default: 10, max: 100)
&sort=name     # field untuk sorting
&order=asc     # asc atau desc

Scopes & Permissions

Setiap API key memiliki scope spesifik yang membatasi akses. Pilih scope minimal yang dibutuhkan (principle of least privilege).

ScopeDeskripsiAkses
students:readMembaca data siswaGET students
students:writeMembuat/memperbarui data siswaPOST/PUT students
students:deleteMenghapus data siswaDELETE students
exams:readMembaca data ujianGET exams
exams:writeMembuat/memperbarui ujianPOST/PUT exams
exams:publishPublish/unpublish ujianPOST publish/unpublish
results:readMembaca hasil ujianGET results
analytics:readMengakses data analitikGET analytics
webhooks:manageMengelola webhook endpointsCRUD webhooks

Students API

Kelola data siswa dalam tenant Anda. Mendukung CRUD individual dan bulk import.

List Students

GET/api/v1/enterprise/studentsstudents:read

Mengambil daftar siswa dengan paginasi, filter, dan sorting.

Query Parameterstext
?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
Responsejson
{
  "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, ... }
}

Create Student

POST/api/v1/enterprise/studentsstudents:write

Membuat siswa baru. Email harus unik dalam tenant.

Request Bodyjson
{
  "name": "Budi Santoso",
  "email": "budi@sekolah.sch.id",
  "student_id": "10A-001",
  "student_code": "STD001",
  "category_id": "uuid-kategori"
}

Get / Update / Delete Student

GET/api/v1/enterprise/students/:idstudents:read

Mengambil detail siswa beserta kategori dan statistik.

PUT/api/v1/enterprise/students/:idstudents:write

Memperbarui data siswa (name, email, student_id, student_code, category).

POST/api/v1/enterprise/students/:id/passwordstudents:write

Menetapkan atau mereset password login siswa. Password tidak pernah dikembalikan pada respons.

Request Bodyjson
{
  "password": "PasswordBaru123!"
}

Password harus 12–128 karakter serta mengandung huruf besar, huruf kecil, dan angka.

Responsejson
{
  "success": true,
  "data": {
    "id": "uuid",
    "password_updated": true
  }
}
DELETE/api/v1/enterprise/students/:idstudents:delete

Menghapus siswa secara permanen.

Bulk Import Students

POST/api/v1/enterprise/students/bulkstudents:write

Bulk import hingga 500 siswa. Mendukung mode skip_duplicates dan upsert.

Request Bodyjson
{
  "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"
  }
}
Responsejson
{
  "success": true,
  "data": {
    "created": 45,
    "skipped": 3,
    "updated": 0,
    "errors": []
  }
}

Exams API

Kelola ujian: buat, update, publish/unpublish secara programatis.

List Exams

GET/api/v1/enterprise/examsexams:read

Mengambil daftar ujian dengan filter status, tanggal, pencarian, dan paginasi.

Query Parameterstext
?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

Create Exam

POST/api/v1/enterprise/examsexams:write

Membuat ujian baru. Bisa menyertakan soal inline.

Request Bodyjson
{
  "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
    }
  ]
}

Get / Update / Delete Exam

GET/api/v1/enterprise/exams/:idexams:read

Mengambil detail ujian. Gunakan ?include=questions untuk menyertakan soal.

PUT/api/v1/enterprise/exams/:idexams:write

Memperbarui ujian (title, description, duration, settings, schedule).

DELETE/api/v1/enterprise/exams/:idexams:write

Menghapus ujian beserta semua soalnya.

Publish & Unpublish

POST/api/v1/enterprise/exams/:id/publishexams:publish

Mempublikasikan ujian (harus memiliki minimal 1 soal).

POST/api/v1/enterprise/exams/:id/unpublishexams:publish

Membatalkan publikasi ujian (kembali ke draft).

Results API

Ambil hasil pengerjaan ujian siswa dengan filter dan analitik.

GET/api/v1/enterprise/exams/:id/resultsresults:read

Mengambil hasil ujian tertentu. Filter berdasarkan skor, status, atau tanggal.

Query Parameterstext
?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
Responsejson
{
  "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
    }
  }
}

Analytics API

Akses analitik tenant-wide: overview, performa, dan penggunaan API.

GET/api/v1/enterprise/analyticsanalytics:read

Analitik keseluruhan tenant dengan periode yang bisa disesuaikan.

Query Parameterstext
?period=30d              # 7d, 30d, 90d, 1y
Responsejson
{
  "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
    }
  }
}

Webhooks API

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.

Daftar Event

EventDeskripsi
exam.createdUjian baru dibuat
exam.updatedUjian diperbarui
exam.publishedUjian dipublikasikan
exam.unpublishedPublikasi ujian dibatalkan
exam.deletedUjian dihapus
exam.completedSemua siswa selesai mengerjakan
student.createdSiswa baru ditambahkan
student.updatedData siswa diperbarui
student.deletedSiswa dihapus
student.enrolledSiswa didaftarkan ke ujian
result.gradedHasil ujian dinilai
result.releasedHasil ujian dirilis ke siswa

Manage Webhooks

GET/api/v1/enterprise/webhookswebhooks:manage

Mengambil daftar webhook (secrets di-mask).

POST/api/v1/enterprise/webhookswebhooks:manage

Membuat webhook baru (max 10 per tenant). Secret otomatis di-generate. URL harus HTTPS di production.

Request Bodyjson
{
  "url": "https://yourapp.com/webhooks/pinaga",
  "events": ["exam.published", "result.graded", "student.created"],
  "max_retries": 3,
  "retry_delay_seconds": 60
}
GET/api/v1/enterprise/webhooks/:idwebhooks:manage

Detail webhook. Gunakan ?include=deliveries untuk melihat log pengiriman.

PUT/api/v1/enterprise/webhooks/:idwebhooks:manage

Update webhook (url, events, active status, retry config).

DELETE/api/v1/enterprise/webhooks/:idwebhooks:manage

Hapus webhook dan semua log pengirimannya.

Verifikasi Signature

Setiap webhook request menyertakan header X-Pinaga-Signature berisi HMAC-SHA256 dari payload. Selalu verifikasi signature untuk keamanan.

Verifikasi Webhook (Node.js)javascript
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 });
});
Webhook Payload Formatjson
{
  "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"
}
Webhook akan di-retry hingga 3 kali (configurable) jika endpoint Anda mengembalikan status code 4xx/5xx. Retry dilakukan setelah delay yang dikonfigurasi (default 60 detik).

Error Codes

API menggunakan HTTP status code standar dan menyertakan kode error spesifik:

HTTPCodeDeskripsi
400BAD_REQUESTPayload/parameter tidak valid
401UNAUTHORIZEDAPI key tidak valid atau expired
403FORBIDDENScope tidak mencukupi / IP tidak diizinkan
404NOT_FOUNDResource tidak ditemukan
409CONFLICTDuplikat data (misal email sudah ada)
422VALIDATION_ERRORValidasi input gagal
429RATE_LIMITEDMelebihi batas rate limit
500INTERNAL_ERRORServer error (hubungi support)

SDK & Code Examples

Contoh integrasi dalam berbagai bahasa pemrograman:

JavaScript / Node.js

Fetch API (modern)javascript
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`);

Python

Python (requests)python
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

PHP (cURL)php
<?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');
?>

Butuh Bantuan?

Jika mengalami kendala atau memiliki pertanyaan tentang Enterprise API, silakan hubungi tim support kami.