The OpenKMS API provides a comprehensive RESTful interface for managing knowledge management and training administration functions. Built with FastAPI, it offers automatic OpenAPI/Swagger documentation, type validation, and async operations for optimal performance.
- Development:
http://localhost:8000/api/v1 - Production:
https://api.yourdomain.com/api/v1
- Interactive Swagger UI:
/docs - ReDoc:
/redoc - OpenAPI Schema:
/openapi.json
The API uses JWT (JSON Web Token) authentication for securing endpoints. All protected endpoints require a valid JWT token in the Authorization header.
- User authenticates via
/api/v1/auth/login - Server returns
access_tokenandrefresh_token - Client includes
access_tokenin subsequent requests - Use
refresh_tokento obtain newaccess_tokenwhen expired
Authorization: Bearer <access_token>
- Access Token: Short-lived (15 minutes) token for API requests
- Refresh Token: Long-lived (7 days) token for obtaining new access tokens
All API responses follow a consistent JSON format:
{
"data": {},
"message": "Success message",
"status": "success"
}{
"detail": "Error message",
"status": "error",
"code": "ERROR_CODE"
}- 200 OK: Successful request
- 201 Created: Resource created successfully
- 400 Bad Request: Invalid request data
- 401 Unauthorized: Authentication required
- 403 Forbidden: Insufficient permissions
- 404 Not Found: Resource not found
- 422 Unprocessable Entity: Validation error
- 500 Internal Server Error: Server error
Authenticate user and return JWT tokens.
Request Body:
{
"username": "string",
"password": "string"
}Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"token_type": "bearer",
"user": {
"id": 1,
"username": "johndoe",
"email": "john.doe@example.com",
"full_name": "John Doe",
"role": "EMPLOYEE",
"is_active": true
}
}Status Codes:
200 OK: Authentication successful401 Unauthorized: Invalid credentials422 Unprocessable Entity: Validation error
Register a new user.
Request Body:
{
"username": "string (max 50 chars)",
"email": "valid@email.com",
"full_name": "string",
"password": "string (min 8 chars)",
"office_location": "string (optional)",
"department": "string (optional)"
}Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"token_type": "bearer",
"user": {
"id": 2,
"username": "newuser",
"email": "newuser@example.com",
"full_name": "New User",
"role": "EMPLOYEE",
"is_active": true
}
}Status Codes:
201 Created: User registered successfully400 Bad Request: User already exists422 Unprocessable Entity: Invalid data
Refresh access token using refresh token.
Request Body:
{
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"token_type": "bearer"
}Status Codes:
200 OK: Token refreshed successfully- `401 Unauthorized**: Invalid refresh token
Change user password.
Request Body:
{
"current_password": "string",
"new_password": "string (min 8 chars)"
}Response:
{
"message": "Password changed successfully"
}Status Codes:
200 OK: Password changed successfully400 Bad Request: Current password incorrect422 Unprocessable Entity: Validation error
Get current authenticated user information.
Response:
{
"user": {
"id": 1,
"username": "johndoe",
"email": "john.doe@example.com",
"full_name": "John Doe",
"office_location": "Office A",
"department": "IT",
"role": "EMPLOYEE",
"is_active": true
},
"message": "User information retrieved successfully"
}Status Codes:
200 OK: User information retrieved- `401 Unauthorized**: Not authenticated
Get list of users with pagination and filtering.
Query Parameters:
skip: Number of users to skip (default: 0)limit: Number of users to return (default: 100, max: 1000)active_only: Filter active users (default: true)role: Filter by role (EMPLOYEE, KNOWLEDGE_MANAGER, ADMIN)
Response:
{
"users": [
{
"id": 1,
"username": "johndoe",
"email": "john.doe@example.com",
"full_name": "John Doe",
"office_location": "Office A",
"department": "IT",
"role": "EMPLOYEE",
"is_active": true,
"created_at": "2023-12-01T10:00:00Z"
}
],
"total": 1,
"skip": 0,
"limit": 100
}Status Codes:
200 OK: Users retrieved successfully- `401 Unauthorized**: Not authenticated
403 Forbidden: Insufficient permissions
Get specific user by ID.
Response:
{
"user": {
"id": 1,
"username": "johndoe",
"email": "john.doe@example.com",
"full_name": "John Doe",
"office_location": "Office A",
"department": "IT",
"role": "EMPLOYEE",
"is_active": true,
"created_at": "2023-12-01T10:00:00Z",
"updated_at": "2023-12-01T10:00:00Z"
}
}Status Codes:
200 OK: User retrieved successfully401 Unauthorized: Not authenticated403 Forbidden: Insufficient permissions404 Not Found: User not found
Update user information.
Request Body:
{
"full_name": "string (optional)",
"email": "string (optional)",
"office_location": "string (optional)",
"department": "string (optional)",
"role": "EMPLOYEE|KNOWLEDGE_MANAGER|ADMIN (optional)",
"is_active": "boolean (optional)"
}Response:
{
"user": {
"id": 1,
"username": "johndoe",
"email": "john.doe@example.com",
"full_name": "John Doe",
"office_location": "Office A",
"department": "IT",
"role": "EMPLOYEE",
"is_active": true,
"updated_at": "2023-12-01T10:00:00Z"
},
"message": "User updated successfully"
}Status Codes:
200 OK: User updated successfully401 Unauthorized: Not authenticated- `403 Forbidden**: Insufficient permissions
404 Not Found: User not found422 Unprocessable Entity: Validation error
Delete user (soft delete).
Response:
{
"message": "User deactivated successfully"
}Status Codes:
200 OK: User deactivated successfully401 Unauthorized: Not authenticated403 Forbidden: Insufficient permissions404 Not Found: User not found
Get list of training programs with filtering and search.
Query Parameters:
skip: Number of trainings to skip (default: 0)limit: Number of trainings to return (default: 100, max: 1000)search: Search in title and descriptioncategory: Filter by category (SECURITY, LEADERSHIP, TECHNICAL, COMPLIANCE)level: Filter by level (BEGINNER, INTERMEDIATE, ADVANCED)status: Filter by status (PUBLISHED, DRAFT)instructor_id: Filter by instructor ID
Response:
{
"trainings": [
{
"id": 1,
"title": "Security Awareness Training",
"description": "Comprehensive security awareness training",
"category": "SECURITY",
"level": "BEGINNER",
"status": "PUBLISHED",
"duration_minutes": 120,
"credits": 2,
"instructor_id": 1,
"max_participants": 50,
"created_at": "2023-12-01T10:00:00Z",
"updated_at": "2023-12-01T10:00:00Z"
}
],
"total": 1,
"skip": 0,
"limit": 100
}Status Codes:
200 OK: Trainings retrieved successfully401 Unauthorized: Not authenticated
Get specific training by ID.
Response:
{
"training": {
"id": 1,
"title": "Security Awareness Training",
"description": "Comprehensive security awareness training",
"category": "SECURITY",
"level": "BEGINNER",
"status": "PUBLISHED",
"duration_minutes": 120,
"credits": 2,
"instructor_id": 1,
"max_participants": 50,
"created_at": "2023-12-01T10:00:00Z",
"updated_at": "2023-12-01T10:00:00Z"
}
}Status Codes:
200 OK: Training retrieved successfully401 Unauthorized: Not authenticated404 Not Found: Training not found
Create new training program.
Request Body:
{
"title": "string",
"description": "string",
"category": "SECURITY|LEADERSHIP|TECHNICAL|COMPLIANCE",
"level": "BEGINNER|INTERMEDIATE|ADVANCED",
"status": "PUBLISHED|DRAFT",
"duration_minutes": "integer",
"credits": "integer",
"max_participants": "integer"
}Response:
{
"training": {
"id": 2,
"title": "New Training Program",
"description": "Training description",
"category": "TECHNICAL",
"level": "INTERMEDIATE",
"status": "DRAFT",
"duration_minutes": 180,
"credits": 3,
"instructor_id": 1,
"max_participants": 30,
"created_at": "2023-12-01T10:00:00Z"
},
"message": "Training created successfully"
}Status Codes:
201 Created: Training created successfully401 Unauthorized: Not authenticated403 Forbidden: Insufficient permissions422 Unprocessable Entity: Validation error
Update training program.
Request Body:
{
"title": "string (optional)",
"description": "string (optional)",
"category": "SECURITY|LEADERSHIP|TECHNICAL|COMPLIANCE (optional)",
"level": "BEGINNER|INTERMEDIATE|ADVANCED (optional)",
"status": "PUBLISHED|DRAFT (optional)",
"duration_minutes": "integer (optional)",
"credits": "integer (optional)",
"max_participants": "integer (optional)"
}Response:
{
"training": {
"id": 1,
"title": "Updated Training Program",
"description": "Updated description",
"category": "SECURITY",
"level": "BEGINNER",
"status": "PUBLISHED",
"duration_minutes": 120,
"credits": 2,
"instructor_id": 1,
"max_participants": 50,
"updated_at": "2023-12-01T10:00:00Z"
},
"message": "Training updated successfully"
}Status Codes:
200 OK: Training updated successfully401 Unauthorized: Not authenticated403 Forbidden: Insufficient permissions404 Not Found: Training not found422 Unprocessable Entity: Validation error
Delete training program.
Response:
{
"message": "Training deleted successfully"
}Status Codes:
200 OK: Training deleted successfully401 Unauthorized: Not authenticated403 Forbidden: Insufficient permissions404 Not Found: Training not found
Get training registrations with filtering.
Query Parameters:
skip: Number of registrations to skip (default: 0)limit: Number of registrations to return (default: 100, max: 1000)user_id: Filter by user IDtraining_id: Filter by training IDstatus: Filter by status (REGISTERED, ATTENDED, CANCELLED, COMPLETED)
Response:
{
"registrations": [
{
"id": 1,
"user_id": 1,
"training_id": 1,
"status": "REGISTERED",
"registered_at": "2023-12-01T10:00:00Z",
"attended_at": null,
"completion_date": null,
"feedback_score": null
}
],
"total": 1,
"skip": 0,
"limit": 100
}Status Codes:
200 OK: Registrations retrieved successfully401 Unauthorized: Not authenticated
Get specific registration by ID.
Response:
{
"registration": {
"id": 1,
"user_id": 1,
"training_id": 1,
"status": "REGISTERED",
"registered_at": "2023-12-01T10:00:00Z",
"attended_at": null,
"completion_date": null,
"feedback_score": null
}
}Status Codes:
200 OK: Registration retrieved successfully- `401 Unauthorized**: Not authenticated
404 Not Found: Registration not found
Register for a training program.
Request Body:
{
"training_id": "integer"
}Response:
{
"registration": {
"id": 2,
"user_id": 1,
"training_id": 2,
"status": "REGISTERED",
"registered_at": "2023-12-01T10:00:00Z",
"attended_at": null,
"completion_date": null,
"feedback_score": null
},
"message": "Registration successful"
}Status Codes:
201 Created: Registration successful- `400 Bad Request**: Already registered or training full
401 Unauthorized: Not authenticated404 Not Found: Training not found- `422 Unprocessable Entity**: Validation error
Update registration status.
Request Body:
{
"status": "REGISTERED|ATTENDED|CANCELLED|COMPLETED",
"feedback_score": "integer (optional, 1-5)"
}Response:
{
"registration": {
"id": 1,
"user_id": 1,
"training_id": 1,
"status": "ATTENDED",
"registered_at": "2023-12-01T10:00:00Z",
"attended_at": "2023-12-01T10:00:00Z",
"completion_date": null,
"feedback_score": null
},
"message": "Registration updated successfully"
}Status Codes:
200 OK: Registration updated successfully401 Unauthorized: Not authenticated403 Forbidden: Insufficient permissions404 Not Found: Registration not found422 Unprocessable Entity: Validation error
Cancel registration.
Response:
{
"message": "Registration cancelled successfully"
}Status Codes:
200 OK: Registration cancelled successfully401 Unauthorized: Not authenticated404 Not Found: Registration not found
{
"roles": [
"EMPLOYEE",
"KNOWLEDGE_MANAGER",
"ADMIN"
]
}{
"categories": [
"SECURITY",
"LEADERSHIP",
"TECHNICAL",
"COMPLIANCE"
]
}{
"levels": [
"BEGINNER",
"INTERMEDIATE",
"ADVANCED"
]
}{
"statuses": [
"REGISTERED",
"ATTENDED",
"CANCELLED",
"COMPLETED"
]
}The API returns detailed error information for troubleshooting:
{
"detail": [
{
"loc": ["body", "password"],
"msg": "ensure this value has at least 8 characters",
"type": "value_error.any_str.min_length"
}
]
}{
"detail": "Could not validate credentials"
}{
"detail": "Not authorized to perform this action"
}{
"detail": "User with id 999 not found"
}The API implements rate limiting to prevent abuse:
- Authentication endpoints: 5 requests per minute
- User management: 100 requests per minute
- Training management: 200 requests per minute
- Registration endpoints: 100 requests per minute
Rate limit headers are included in responses:
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Remaining requestsX-RateLimit-Reset: Time when limit resets (UTC timestamp)
List endpoints support pagination using skip and limit parameters:
GET /api/v1/users?skip=0&limit=10
{
"users": [...],
"total": 150,
"skip": 0,
"limit": 10
}- Use
skipandlimitfor large datasets - Don't request more than 1000 items per request
- Implement client-side pagination for better UX
- Use
totalfield to calculate page numbers
The API supports webhooks for real-time notifications:
user.registered: New user registrationtraining.created: New training program createdregistration.completed: Training registration completed
Configure webhook URLs in the application settings. Webhooks are sent as POST requests with event payload in JSON format.
{
"event": "training.created",
"timestamp": "2023-12-01T10:00:00Z",
"data": {
"training_id": 1,
"title": "New Training Program",
"created_by": 1
}
}import requests
class OpenKMSAPI:
def __init__(self, base_url, api_key):
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({"Authorization": f"Bearer {api_key}"})
def get_users(self):
response = self.session.get(f"{self.base_url}/api/v1/users")
return response.json()class OpenKMSAPI {
constructor(baseUrl, apiKey) {
this.baseUrl = baseUrl;
this.headers = { 'Authorization': `Bearer ${apiKey}` };
}
async getUsers() {
const response = await fetch(`${this.baseUrl}/api/v1/users`, {
headers: this.headers
});
return response.json();
}
}- Initial API release
- User management endpoints
- Training management endpoints
- Registration management endpoints
- JWT authentication
- OpenAPI documentation
For API support and questions:
- Documentation: See
/docsendpoint for interactive documentation - Issues: Report bugs at GitHub Issues
- Email: support@openkms.com
Last updated: December 1, 2023