Overview
The School Records API is one REST endpoint per record type. You send JSON arrays of records; eKTextAI stores them in that school's own database and answers parents and staff from them. Each parent only ever hears about their own child; class ranks, averages and private fields are never stored.
| What | Value |
|---|---|
| Base URL | https://ektextai.com/api/sis/v1 |
| Format | JSON over HTTPS, TLS 1.2 or later |
| Push | POST /{record type} with a JSON array, up to 1,000 records |
| Check | GET /state for the last push per type; GET /schema for the types |
| Reference integration | SchoolAdmin, MarvelSoft's own school software, uses this same API |
Become a partner
Partners earn a share of every eKTextAI plan their schools pay for. Joining takes four steps.
- Apply. Create your account on the MarvelSoft Partner Portal with your company, your software and roughly how many schools use it. Questions first? Use the contact form.
- Sandbox. Once we approve you, the portal shows your Partner ID (
ptr_…) and lets you create the key of a sandbox school that is yours to test with. Sandbox schools never count toward billing. - Certification. Pass the go-live checklist against your sandbox school.
- Live. Once certified, any school that connects your software can send its records through you.
Authentication
Every request carries two credentials. The school key says which school; your Partner ID says which vendor. Neither works alone: a school key created for one partner is refused with another Partner ID, and a Partner ID never opens a school by itself.
| Header | Value | Where it comes from |
|---|---|---|
x-api-keyor Authorization: Bearer … | The school's key | The school creates it for your software and gives it to you. Keep it secret, per school, server side only. |
X-Partner-Id | Your Partner ID, ptr_ + 16 characters | From us when you are approved. It is public, not a secret: the same on every school. |
X-School-Id | Optional: your id for the school | If you send org_id on records, it must match this school. |
Content-Type | application/json |
Never ship a school key inside an app, a browser page or a mobile app. A leaked key can be revoked by the school at any time; ask the school for a new one.
Plans and limits
A school that has not chosen a paid eKTextAI plan is in test mode, for testing and demos. The school pays eKTextAI for its plan; you never collect money for us.
| School | Students synced | Enquiring parents |
|---|---|---|
| Test mode (free) | Up to 50 active students; parents of these students get answers from your data | Up to 200 prospective parents asking about admissions, fees or the school |
| Paid plan (Business, Growth, Enterprise) | No limit | The plan's own limit |
In test mode the 51st active student and later ones are not stored: they come back in data.errors with code TEST_MODE_LIMIT, and the rest of the request is stored. Students marked "status": "left" do not count.
| Limit | Value |
|---|---|
| Records per request | 1,000 (plus the two markers of a full replace) |
| Requests per minute, per school | 120 |
| Requests per minute, all your schools together | 600 by default; ask us for more |
Rate limits answer HTTP 429 with RateLimit headers; wait and retry.
How a push works
Records are keyed and idempotent
Every record type has a key field, your own id for the row (see Record types). Sending a record again with the same key replaces it; sending it unchanged costs nothing. You can retry any failed request safely.
Changes only
Send the new and changed records. To remove one, send its key with "deleted": true.
Full replace (recommended once a day)
Send the whole list, and eKTextAI removes whatever you did not send. That is how students who left, cancelled homework or corrected marks disappear without you tracking deletes.
- Pick a run id, for example
GVPS01-user_details-1731400000000. - The first request starts with
{"droptable": true, "push_run": "<run id>"}. - Send the records in requests of up to 1,000.
- The last request ends with
{"complete": true, "push_run": "<run id>"}.
Nothing is removed until complete arrives, so a push that fails halfway removes nothing; start a new run. Add "scope" to the droptable marker to replace only part of a type, for example {"main_group": "5"} for one class, or {"from": "2026-11-01", "to": "2026-11-30"} for one month of attendance.
Order
Push school details first, then students, then parents, then everything else. Parents are recognised by the mobile number or email on their guardians record.
exams record has a published_at date on or before today (India time). Push the exam record when the school releases the results.Quick start and samples
Each sample does a full replace of students for one school: start marker, records, end marker. Replace the key and Partner ID with your sandbox values.
The reply
Check data.failed and data.errors on every reply; an HTTP 200 with "info": "partial" means some records were not stored.
Record types
Field names are the ones SchoolAdmin sends; some are upper case for historical reasons. Fields not listed are stored as sent, except the private ones under Privacy, which are always removed. Every record may also carry org_id and deleted.
Loading the reference…
Errors
Every reply has the shape { "result": true|false, "info": "<code>", "message": "…", "data": … }.
The whole request is refused
| HTTP | info | When |
|---|
One record is refused (in data.errors)
code | When |
|---|
Privacy
The school is the data fiduciary under India's DPDP Act, 2023; MarvelSoft processes the data on the school's behalf (School Data Statement). As the school's software vendor you send the data on the school's instructions.
- Each school's records live in a database of their own.
- A parent is answered only about the students they are a guardian of.
- Group data is never stored: class rank, class average, class size, percentile, topper.
- These fields are removed from every record, whatever the record type: .
Do not send what you do not need. Date of birth, address and photos are not needed for any answer.
Go-live checklist
Show us these against your sandbox school to be certified.
- A full replace of
user_details(students), then a second one with one student left out:GET /stateshows it removed. - Pushes of
guardians,attendance,exams(withpublished_at) andmarks. - A push split over several requests of 1,000, with the markers in the first and the last.
- Refusals handled: a wrong key, a wrong Partner ID, and a record error in
data.errorsshown to the school. - Retries with backoff on HTTP 429 and 5xx.
GET /stateused to show the school when its last sync ran and whether it failed.- School keys stored encrypted, server side, one per school.
Downloads and changelog
- OpenAPI 3.1 spec (JSON): import it into Postman or Insomnia (Import > File), or generate a client in your language with OpenAPI Generator.
- llms.txt: for AI coding assistants reading these docs.
The API is versioned in the path (/v1). We add record types and optional fields without notice; anything that would break an integration comes as /v2, announced to partners at least 90 days before.
| Version | Date | Change |
|---|
Questions: info@ektextai.com.