ERP Partner Integration
This section is for ERP and SIS providers embedding TimetableMaster inside their own product.
Your users never see a TimetableMaster login, bill, or brand. They stay in your product, on your domain, and open a Timetable area that happens to be powered by us.
The three things you build
| # | What | Direction | Why |
|---|---|---|---|
| 1 | Launch | You → us | Sign a user in from your ERP, with no login screen |
| 2 | Entity sync | You → us | Keep teachers, subjects, classes and rooms current |
| 3 | Reading schedules | Us → you | Pull the generated timetable back into your product |
Build them in that order. Launch is testable on its own with curl, and sync is the largest piece.
Base URL and authentication
All partner endpoints live under /api/partner/v1 and take your organisation's API key:
Authorization: Bearer ttm_<your api key>
These calls are server-to-server only. The API key must never reach a browser. It authorises everything in the organisation, including minting a session for any user. See Authentication.
We create one organisation per customer institution and issue you an API key for each. There is no self-service organisation creation.
Identifiers: the one thing to get right
Every entity you send us carries your identifier in externalId. We store it, treat it as the
entity's identity for all future syncs, and return it on every entity in every read response.
That means you never build a mapping table. You send EMP-1001, and when you ask what teacher
EMP-1001 is teaching, you get an answer in those terms.
Internally we also use a localId, an identifier scoped to a single timetable. Lesson units
reference entities by localId, and the entity lists let you resolve localId → externalId. You
only need localId to join a unit to an entity within one timetable response.
| Identifier | Whose | Scope | You use it for |
|---|---|---|---|
externalId | Yours | Your system | Addressing entities, joining our data to your records |
localId | Ours | One timetable | Resolving references inside a timetable response |
Response envelope
Every endpoint returns:
{
"success": true,
"data": { },
"timestamp": "2026-09-14T10:00:00.000Z"
}
Errors:
{
"success": false,
"error": { "code": "PARTNER_ACCESS_DISABLED", "message": "Partner access is not enabled for this organisation" },
"timestamp": "2026-09-14T10:00:00.000Z"
}
Always branch on error.code, never on the message text.
Common error codes
| Code | Status | Meaning |
|---|---|---|
PARTNER_ACCESS_DISABLED | 403 | The organisation is not enabled for partner access |
SYNC_IN_PROGRESS | 409 | Another sync is running for this organisation and entity type |
MASS_RETIRE_BLOCKED | 409 | A snapshot would retire too much. See Entity sync |
INVALID_LAUNCH_TOKEN | 401 | The launch token was already used, expired, or never existed |
UNKNOWN_ENTITY_TYPE | 400 | Not one of teachers, subjects, rooms, classes, students |