Portal API overview
A JSON API for systems without OneRoster to read and send students, seasons and enrollments.
Not every school system supports OneRoster. The portal API (v1) is a plain JSON REST API that lets the school's software read and send internship data: students, seasons, season enrollments, account blocks; and read internship results and approved companies. It also accepts OneRoster CSV packages from software that can export them but has no OneRoster API.
Systems that support OneRoster 1.2 should read through the OneRoster API. Both APIs share connections, scopes and limits.
At a glance
- Base URL:
https://<trường>.<tên-miền-nền-tảng>/integration/v1. The school is identified by the domain; a token only works at the school that issued it. - Format: JSON, UTF-8. Instants in ISO 8601 (UTC); dates (
startDate,endDate) asYYYY-MM-DDin Vietnam time. - Errors: Problem Details (RFC 9457),
application/problem+json. See Limits and errors. - Machine-readable description: OpenAPI 3.1 at
/integration/v1/openapi.json.
Authentication
Every call sends Authorization: Bearer <token>. The school creates a connection under Kết nối hệ thống and chooses one of two kinds:
| Connection kind | How it works | Suits |
|---|---|---|
| Access token | One ttdn_pat_... token sent with every call. Optional expiry (30, 90, 180, 365 days) or none. | Simple systems, sync scripts |
| Client id and secret | Get a one-hour token at /oauth/token with OAuth 2.0 Client Credentials, as for OneRoster. | Systems used to OAuth 2.0 |
curl -H "Authorization: Bearer ACCESS_TOKEN" \
"https://<trường>.<tên-miền-nền-tảng>/integration/v1/seasons"- Rotation: the school presses Thay khoá to issue a new token (or secret); the old one keeps working for 24 hours.
- Revocation: stops every token of the connection at once; it cannot be undone.
- Address allowlist: if the school lists network addresses (IPv4/IPv6, CIDR such as
203.0.113.0/24), calls from other addresses get403.
Tokens and secrets are shown only once. Keep them in environment variables or a secret store, never in source code or unencrypted messages.
Scopes
| Scope | Allows |
|---|---|
students:read | Read students |
students:write | Create, update, block, unblock students |
seasons:read | Read seasons |
seasons:write | Create and update seasons from the school's terms |
enrollments:read | Read the students of a season |
enrollments:write | Admit students to a season |
results:read | Read internship results |
companies:read | Read the companies approved for a season |
imports:write | Send OneRoster CSV packages |
Checking jobs (/jobs/...) needs any write scope: students:write, enrollments:write or imports:write. A missing scope returns 403 naming the scope needed.
Conventions
Paging
Long lists (/students, /seasons/{id}/enrollments, /seasons/{id}/results) come in pages:
limit: 1 to 500, default 100.- The body has
next: the cursor of the next page, ornullat the end. Send it back as?cursor=<next>with the same parameters. - The
Link: <...>; rel="next"header (RFC 8288) holds the next page's URL.
Syncing changes
GET /students?updatedSince=2026-11-01T00:00:00Z returns only students changed since then. Store the time each sync starts and use it next time.
Dry runs
Every write accepts ?dryRun=true: the portal checks and answers as if for real but saves nothing.
Safe retries
Batch writes (POST) accept an Idempotency-Key header (1 to 255 characters; a UUID is best). Resending with the same key within 24 hours returns the first answer (with Idempotent-Replayed: true) and creates no new job. The same key with a different body is refused (422).
Identifiers
- Students are identified by student code (
studentCode, case-insensitive). externalId(optional, up to 128 characters) is the record's id in the school's system. Once sent, the portal matches students by it first, then by student code, then by email.- Seasons have a portal
idand anexternalId: the term's id in the school's system.
Endpoint groups
| Group | Page |
|---|---|
| Read seasons, students, enrollments, results, companies | Reading data |
| Send seasons, students, enrollments, blocks; follow jobs | Sending data |
| Send OneRoster CSV packages | OneRoster CSV packages |