Authentication
The TimetableMaster API uses API key authentication to secure access to your timetable data. This guide will help you set up authentication for your applications.
Generating an API Key
API access is switched on per organisation. If a key is refused with "API access is not enabled for this organisation", contact support to have it enabled.
Step 1: Access Your Dashboard
- Log in to your TimetableMaster account
- Navigate to Settings → API Keys
- Click Generate New API Key
Step 2: Configure Your API Key
- Name: Give your API key a descriptive name (e.g., "School Website", "Mobile App")
- Expires At: Optionally set an expiration date for enhanced security
Step 3: Save Your API Key
Important: Copy and store your API key securely immediately after generation. For security reasons, you won't be able to view the full key again.
ttm_1234567890abcdef1234567890abcdef12345678
Using Your API Key
Authentication Header
Include your API key in the Authorization header of every API request:
Authorization: Bearer ttm_1234567890abcdef1234567890abcdef12345678
Example Request
curl -H "Authorization: Bearer ttm_1234567890abcdef1234567890abcdef12345678" \
-H "Content-Type: application/json" \
https://api.timetablemaster.com/api/v1/timetables
Security Best Practices
Environment Variables
Store your API key in environment variables, never hardcode it in your application:
// ✅ Good
const apiKey = process.env.TIMETABLE_API_KEY;
// ❌ Bad
const apiKey = "ttm_1234567890abcdef..."; // Never do this!
Secure Storage
- Use secure environment variable management
- Never commit API keys to version control
- Rotate keys regularly for enhanced security
- Use different keys for different environments (development, staging, production)
Network Security
- Always use HTTPS for API requests
- Implement proper error handling to avoid exposing keys in logs
- Consider IP restrictions if your application runs from fixed locations
Key Management
Multiple Keys
You can create multiple API keys for different purposes:
- One for your website integration
- Another for your mobile app
- Separate keys for development and production
Key Rotation
Regularly rotate your API keys for security:
- Generate a new API key
- Update your applications to use the new key
- Revoke the old key once all applications are updated
Revoking Keys
If a key is compromised or no longer needed:
- Go to Settings → API Keys
- Find the key and click Revoke
- The key will be immediately deactivated
Authentication Errors
Key and access errors (401)
Every problem with the key itself returns 401 with the code INVALID_API_KEY. The message
says which problem it is:
message | Cause |
|---|---|
Invalid or inactive API key | The key does not exist or was revoked |
API key has expired | The key's expiry date has passed. Generate a new one |
API access is not enabled for this organisation. Contact support to request it. | API access is switched off for your organisation. Keys issued earlier stop working too |
Authentication required | No Authorization: Bearer ttm_… header was sent |
{
"success": false,
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid or inactive API key"
},
"timestamp": "2026-10-06T10:00:00.000Z"
}
Access ended (402)
When your organisation's access has ended (the trial is over, or the plan was not renewed) or the
account is suspended, every request returns 402, whatever the key. This body has a different
shape from other errors: error is the message itself, not an object.
{
"code": "ACCESS_EXPIRED",
"access": "locked",
"lockedBecause": "plan_ended",
"error": "Your plan was not renewed. Renew to keep using TimetableMaster."
}
| Field | Values |
|---|---|
code | ACCESS_EXPIRED, or ACCOUNT_SUSPENDED |
access | locked or suspended |
lockedBecause | trial_ended, plan_ended or payment_failed; null when suspended |
The same key works again as soon as access is restored. You do not need a new one.
Testing Your Authentication
Quick Test
Test your API key with this simple request:
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.timetablemaster.com/api/v1/timetables
Expected Response
If authentication is successful, you'll receive your organisation's timetable versions:
{
"success": true,
"data": {
"orgId": "6913a0c4e1b2f3a4b5c6d7e8",
"count": 1,
"timetables": [
{
"id": "6a34108b1d16898202940188",
"name": "Term 1 2026",
"groupId": "6a3410551d16898202940101",
"versionNumber": 3,
"versionName": null,
"status": "published",
"isCurrent": true,
"publishedAt": "2026-08-28T07:15:00.000Z",
"effectiveFrom": 20260901,
"effectiveTo": null,
"schedulingMode": "standard",
"createdAt": "2026-07-01T09:12:00.000Z",
"updatedAt": "2026-08-28T07:15:00.000Z"
}
]
},
"timestamp": "2026-10-06T10:00:00.000Z"
}
See List Timetables for every field.
Programming Language Examples
JavaScript/Node.js
const axios = require("axios");
const apiKey = process.env.TIMETABLE_API_KEY;
const baseURL = "https://api.timetablemaster.com/api/v1";
const api = axios.create({
baseURL,
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
});
// Usage
async function getTimetables() {
try {
const response = await api.get("/timetables");
return response.data;
} catch (error) {
console.error("API Error:", error.response.data);
throw error;
}
}
Python
import requests
import os
API_KEY = os.getenv('TIMETABLE_API_KEY')
BASE_URL = 'https://api.timetablemaster.com/api/v1'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
def get_timetables():
response = requests.get(f'{BASE_URL}/timetables', headers=headers)
if response.status_code == 200:
return response.json()
else:
print(f'Error: {response.status_code} - {response.json()}')
return None
PHP
<?php
$apiKey = $_ENV['TIMETABLE_API_KEY'];
$baseUrl = 'https://api.timetablemaster.com/api/v1';
$headers = [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
];
function getTimetables() {
global $baseUrl, $headers;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $baseUrl . '/timetables');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
return json_decode($response, true);
}
return null;
}
?>
Next: Learn how to make your first API request and explore the available endpoints.