EduSeat Public API
The EduSeat Public API lets your university's student information system (SIS) or admissions portal integrate directly with EduSeat's attendance platform. Sync student rosters, register courses, manage enrollments, and pull attendance and barring data programmatically — no manual CSV uploads required.
Authentication
Every university is issued a single long-lived api_key by an EduSeat Super Admin (Super Admin panel → API Keys). Exchange it for a short-lived bearer token by calling POST /auth, then send that token as Authorization: Bearer <token> on every subsequent request.
curl -X POST https://www.eduseat.ng/api/v1/auth \
-H "Content-Type: application/json" \
-d '{
"api_key": "eduseat_live_xxxxxxxxxxxxxxxxxxxx"
}'curl https://www.eduseat.ng/api/v1/students?matric=CSC/2021/001 \
-H "Authorization: Bearer eyJ1aWQiOiI...<token>"Tokens expire after 24 hours (returned as expires_in in seconds). There is no refresh endpoint — simply call POST /auth again with your api_key to get a new one. Treat both your api_key and issued tokens as secrets — never expose them in client-side code.
Base URL
All endpoints below are relative to this base URL. Every response — success or error — is JSON.
https://www.eduseat.ng/api/v1Endpoints
/authExchange your university's api_key for a bearer token. This is the only endpoint that does not require a token.
{
"api_key": "eduseat_live_xxxxxxxxxxxxxxxxxxxx"
}// 200 OK
{
"success": true,
"data": {
"token": "eyJ1aWQiOiI...<token>",
"expires_in": 86400,
"university_id": "2e1e478e-23ba-4f50-8e73-298311511ff4",
"university_name": "University of Example"
}
}// 401 Unauthorized
{
"success": false,
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}/studentsRequires Bearer tokenCreate a new student, or update an existing one (matched by matric_number). Creating a student provisions a real EduSeat login for them.
{
"matric_number": "CSC/2021/001",
"full_name": "Jane Doe",
"email": "jane.doe@university.edu.ng",
"level": "300",
"department": "Computer Science"
}// 201 Created
{
"success": true,
"data": {
"action": "created",
"student": {
"id": "fd096a8e-3d39-4efc-840c-163c8d8356b2",
"matric_number": "CSC/2021/001",
"full_name": "Jane Doe",
"email": "jane.doe@university.edu.ng",
"level": "300",
"department": "Computer Science"
}
}
}email is optional — omit it and EduSeat auto-generates a @eduseat.ng address from the matric number. If you provide an institutional email, EduSeat sends the student a one-time setup link. Calling this again with the same matric_number updates the record instead ("action": "updated", HTTP 200) and never touches login credentials. There is also a matching GET /students?matric= to fetch a student plus their attendance summary.
/students/bulkRequires Bearer tokenCreate or update up to thousands of students in one call, processed in internal batches of 50.
{
"students": [
{ "matric_number": "CSC/2021/001", "full_name": "Jane Doe", "level": "300", "department": "Computer Science" },
{ "matric_number": "CSC/2021/002", "full_name": "John Smith", "level": "300", "department": "Computer Science" }
]
}// 200 OK
{
"success": true,
"data": {
"created": 2,
"updated": 0,
"failed": 0,
"errors": []
}
}A failure on one row (e.g. a duplicate email) never fails the whole batch — check the errors array, keyed by matric_number, for anything that needs attention.
/courses/bulkRequires Bearer tokenCreate or update courses in bulk, matched by course_code. There is also a single-course POST /courses and GET /courses?code=.
{
"courses": [
{
"course_code": "CSC301",
"course_name": "Operating Systems",
"level": "300",
"department": "Computer Science",
"faculty": "Science",
"semester": "first"
}
]
}// 200 OK
{
"success": true,
"data": {
"created": 1,
"updated": 0,
"failed": 0,
"errors": []
}
}Updating an existing course only overwrites the fields you send — omitted fields keep their current value.
/enrollments/bulkRequires Bearer tokenEnroll students into courses in bulk, referencing both sides by their public identifiers.
{
"enrollments": [
{ "matric_number": "CSC/2021/001", "course_code": "CSC301" },
{ "matric_number": "CSC/2021/002", "course_code": "CSC301" }
]
}// 200 OK
{
"success": true,
"data": {
"enrolled": 2,
"skipped": 0,
"failed": 0,
"errors": []
}
}Already-enrolled pairs count toward skipped, not failed — this is safe to call repeatedly. Single enroll/unenroll is available at POST/DELETE /enrollments with the same { matric_number, course_code } body.
/attendance?matric=CSC/2021/001Requires Bearer tokenGet a student's full attendance record — a per-course summary plus every individual check-in.
// 200 OK
{
"success": true,
"data": {
"matric_number": "CSC/2021/001",
"courses": [
{
"course_id": "1f4dfdb9-44da-46df-9fc9-ca95c88515b4",
"course_code": "CSC301",
"course_name": "Operating Systems",
"faculty": "Science",
"total_sessions": 12,
"attended_sessions": 10,
"attendance_percentage": 83.33
}
],
"records": [
{ "id": "...", "session_id": "...", "course_id": "...", "checked_in_at": "2026-03-04T09:02:11Z", "status": "present" }
]
}
}Swap the query for ?course=CSC301 to instead get every enrolled student's attendance for one course.
/attendance/barring-list?threshold=75Requires Bearer tokenList every student below a given attendance percentage, across all their courses — the source of truth for exam-barring decisions. Uses the attendance_summary view.
// 200 OK
{
"success": true,
"data": {
"threshold": 75,
"count": 2,
"students": [
{ "matric_number": "CSC/2021/014", "full_name": "Ade Bello", "level": "300", "course_code": "CSC301", "attendance_percentage": 62.5 },
{ "matric_number": "CSC/2021/029", "full_name": "Amaka Obi", "level": "300", "course_code": "CSC305", "attendance_percentage": 70 }
]
}
}threshold defaults to 75 if omitted. One row is returned per student per course they're below threshold in.
/webhooksRequires Bearer tokenRegister a webhook URL to receive push notifications instead of polling. There is also a GET /webhooks to list your university's registered webhooks.
{
"url": "https://portal.university.edu.ng/webhooks/eduseat",
"events": ["attendance.recorded", "session.ended", "student.status_changed"]
}// 201 Created
{
"success": true,
"data": {
"id": "9c2f...",
"url": "https://portal.university.edu.ng/webhooks/eduseat",
"events": ["attendance.recorded", "session.ended", "student.status_changed"],
"is_active": true,
"created_at": "2026-09-07T08:00:00Z",
"secret": "5f2b9e... (shown once — save it)"
}
}secret is returned only at creation time — store it to verify the X-EduSeat-Signature header (sha256=<hmac>, HMAC-SHA256 of the raw JSON body) on delivered payloads. Every delivery also carries X-EduSeat-Event and a unique X-EduSeat-Delivery id; a failed delivery (non-2xx, timeout, or network error) is retried once. Valid events: attendance.recorded, barring.updated, session.started, session.ended, student.status_changed, student.synced.
Error Codes
Every error response has the shape below. Check code programmatically — the error string is for humans and may change wording over time.
{
"success": false,
"error": "Human-readable message",
"code": "MACHINE_READABLE_CODE"
}| Code | HTTP Status | Meaning |
|---|---|---|
| UNAUTHORIZED | 401 | Missing or malformed Authorization header — expected "Bearer <token>". |
| INVALID_TOKEN | 401 | The bearer token is malformed or its signature does not match. |
| TOKEN_EXPIRED | 401 | The bearer token has expired. Call POST /auth again with your api_key. |
| INVALID_API_KEY | 401 | The api_key was not recognized, or has been revoked. |
| INVALID_INPUT | 400 | The request body is missing required fields or is malformed. |
| NOT_FOUND | 404 | The requested student or course does not exist. |
| STUDENT_NOT_FOUND | 404 | No student matches the given matric_number. |
| COURSE_NOT_FOUND | 404 | No course matches the given course_code. |
| DUPLICATE_EMAIL | 409 | That email is already registered to a different account. |
| DUPLICATE_STUDENT | 409 | A student with this matric_number already exists. |
| AUTH_CREATE_FAILED | 500 | Couldn't create the student's login account. Retry, or contact support@eduseat.ng if it persists. |
| DB_ERROR | 500 | A database error occurred while processing the request. |
| RATE_LIMITED | 429 | You exceeded 100 requests per minute for this API key. Back off and retry. |
| SERVER_MISCONFIGURED | 500 | The server is missing required configuration. Contact support@eduseat.ng. |
| INTERNAL_ERROR | 500 | An unexpected error occurred. |
Rate Limits
Each API key is limited to 100 requests per minute. The window is a fixed 60-second bucket per key, not a sliding average. Exceeding it returns:
// 429 Too Many Requests
{
"success": false,
"error": "Rate limit exceeded: max 100 requests per minute",
"code": "RATE_LIMITED"
}Prefer the bulk endpoints (/students/bulk, /courses/bulk, /enrollments/bulk) over looping single-record calls — one bulk call moves hundreds of records without touching the limit. On a 429, back off and retry after a few seconds rather than retrying immediately.
Legal
Before integrating with the EduSeat Public API, review the agreements governing how data accessed through it may be used.
Technical questions about the API? Email support@eduseat.ng. For legal, data, or partnership enquiries, use contact@eduseat.ng.