{"openapi":"3.0.3","info":{"title":"Elephant Public API","version":"1.0.0"},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","name":"X-API-Key","in":"header"}},"schemas":{}},"paths":{"/v1/users/":{"get":{"summary":"List users","tags":["Users"],"description":"Retrieve a paginated list of users with optional filtering","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"in":"query","name":"pageSize","required":false},{"schema":{"type":"string"},"in":"query","name":"team","required":false},{"schema":{"type":"string"},"in":"query","name":"email","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email","nullable":true},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"team":{"type":"string"},"tenant":{"type":"string"},"language":{"type":"string"},"phoneNumber":{"type":"string","nullable":true,"description":"Format: E.164 (e.g., +1234567890)"},"startDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"endDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD). Null when the user has no scheduled deactivation."},"isActive":{"type":"boolean"},"insertedAt":{"type":"string"},"tags":{"type":"array","items":{"type":"object","properties":{"tagId":{"type":"string","format":"uuid"},"label":{"type":"string"}},"required":["tagId","label"],"additionalProperties":false}}},"required":["userId","email","firstName","lastName","team","tenant","language","phoneNumber","startDate","endDate","isActive","insertedAt","tags"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"number"},"pageSize":{"type":"number"},"total":{"type":"number"},"totalPages":{"type":"number"}},"required":["page","pageSize","total","totalPages"],"additionalProperties":false}},"required":["data","pagination"],"additionalProperties":false}}}}}},"post":{"summary":"Create user","tags":["Users"],"description":"Create a new user. If a user with the same email already exists, the response includes `wasExisting: true` and no fields are updated — including `isActive`. To deactivate or reactivate an existing user, use `PATCH /v1/users/{userId}` instead.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":8},"firstName":{"type":"string","minLength":1},"lastName":{"type":"string","minLength":1},"team":{"type":"string","minLength":1},"language":{"type":"string","minLength":2,"maxLength":10,"default":"en_GB"},"phoneNumber":{"type":"string","description":"Format: E.164 (e.g., +1234567890)"},"startDate":{"type":"string","description":"Format: ISO 8601 date (YYYY-MM-DD)"},"endDate":{"type":"string","description":"Format: ISO 8601 date (YYYY-MM-DD)"},"isActive":{"type":"boolean","description":"Defaults to true. Set to false to create the user in a deactivated state."},"tags":{"type":"array","items":{"type":"string"},"description":"Roles assigned to the user"}},"required":["email","password","firstName","lastName","team"],"additionalProperties":false}}}},"security":[{"apiKey":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"wasExisting":{"type":"boolean"}},"required":["userId","wasExisting"],"additionalProperties":false}}}}}}},"/v1/users/{userId}":{"get":{"summary":"Get user by ID","tags":["Users"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"userId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email","nullable":true},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"team":{"type":"string"},"tenant":{"type":"string"},"language":{"type":"string"},"phoneNumber":{"type":"string","nullable":true,"description":"Format: E.164 (e.g., +1234567890)"},"startDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"endDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD). Null when the user has no scheduled deactivation."},"isActive":{"type":"boolean"},"insertedAt":{"type":"string"},"tags":{"type":"array","items":{"type":"object","properties":{"tagId":{"type":"string","format":"uuid"},"label":{"type":"string"}},"required":["tagId","label"],"additionalProperties":false}}},"required":["userId","email","firstName","lastName","team","tenant","language","phoneNumber","startDate","endDate","isActive","insertedAt","tags"],"additionalProperties":false}}}}}},"patch":{"summary":"Update user","tags":["Users"],"description":"Update user fields. All fields are optional — only provided fields will be changed. Supports updating the user email address; returns 409 if the new email is already taken by another user. To reactivate a deactivated user, send `{ \"isActive\": true }` or `{ \"endDate\": null }`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"firstName":{"type":"string","minLength":1},"lastName":{"type":"string","minLength":1},"team":{"type":"string","minLength":1},"language":{"type":"string","minLength":2,"maxLength":10},"phoneNumber":{"type":"string","nullable":true,"description":"Format: E.164 (e.g., +1234567890)"},"startDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"endDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD). Set to `null` to reactivate a previously deactivated user (clears the end date and re-opens the active period)."},"isActive":{"type":"boolean","description":"Set to true to reactivate a deactivated user, or false to deactivate immediately."},"tags":{"type":"array","items":{"type":"string"},"description":"Roles assigned to the user"}},"additionalProperties":false,"description":"All fields are optional. Only provided fields will be updated."}}},"description":"All fields are optional. Only provided fields will be updated."},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"userId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email","nullable":true},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"team":{"type":"string"},"tenant":{"type":"string"},"language":{"type":"string"},"phoneNumber":{"type":"string","nullable":true,"description":"Format: E.164 (e.g., +1234567890)"},"startDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"endDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD). Null when the user has no scheduled deactivation."},"isActive":{"type":"boolean"},"insertedAt":{"type":"string"},"tags":{"type":"array","items":{"type":"object","properties":{"tagId":{"type":"string","format":"uuid"},"label":{"type":"string"}},"required":["tagId","label"],"additionalProperties":false}}},"required":["userId","email","firstName","lastName","team","tenant","language","phoneNumber","startDate","endDate","isActive","insertedAt","tags"],"additionalProperties":false}}}}}},"delete":{"summary":"Deactivate or permanently delete user","tags":["Users"],"description":"Deactivates a user by default — sets the end of the active period to today, but keeps the user record intact. Deactivated users can be reactivated via `PATCH /v1/users/{userId}` with `{ \"isActive\": true }` or `{ \"endDate\": null }`. Note: re-creating a deactivated user via `POST /v1/users` returns 409 — use PATCH instead. Use `?permanent=true` to permanently delete the user and all associated data (tag assignments, course assignments, course progress, certificates, roles). Permanent deletion cannot be undone.","parameters":[{"schema":{"type":"boolean","default":false},"in":"query","name":"permanent","required":false,"description":"When `true`, hard-deletes the user and cascades to all dependent records (tag assignments, course assignments, course progress, certificates, roles). Cannot be undone. When `false` (default), only deactivates the user — reversible via `PATCH /v1/users/{userId}`."},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"userId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response"}}}},"/v1/languages/":{"get":{"summary":"List languages","tags":["Languages"],"description":"Retrieve available languages for the tenant","security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"languageCode":{"type":"string"},"name":{"type":"string","nullable":true}},"required":["languageCode","name"],"additionalProperties":false}}},"required":["data"],"additionalProperties":false}}}}}}},"/v1/tags/":{"get":{"summary":"List tags","tags":["Tags"],"description":"Retrieve all tags","security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"tagId":{"type":"string","format":"uuid"},"label":{"type":"string"},"insertedAt":{"type":"string"}},"required":["tagId","label","insertedAt"],"additionalProperties":false}}},"required":["data"],"additionalProperties":false}}}}}},"post":{"summary":"Create tag","tags":["Tags"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1}},"required":["label"],"additionalProperties":false}}}},"security":[{"apiKey":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tagId":{"type":"string","format":"uuid"}},"required":["tagId"],"additionalProperties":false}}}}}}},"/v1/tags/{tagId}":{"patch":{"summary":"Update tag","tags":["Tags"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1}},"required":["label"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"tagId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tagId":{"type":"string","format":"uuid"},"label":{"type":"string"},"insertedAt":{"type":"string"}},"required":["tagId","label","insertedAt"],"additionalProperties":false}}}}}}},"/v1/courses/":{"get":{"summary":"List published courses","tags":["Courses"],"description":"Retrieve a paginated list of published courses with title and description from the master language. Only published courses are returned.","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"in":"query","name":"pageSize","required":false}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"courseId":{"type":"string","format":"uuid"},"insertedAt":{"type":"string"},"title":{"type":"string","nullable":true},"description":{"type":"string","nullable":true}},"required":["courseId","insertedAt","title","description"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"number"},"pageSize":{"type":"number"},"total":{"type":"number"},"totalPages":{"type":"number"}},"required":["page","pageSize","total","totalPages"],"additionalProperties":false}},"required":["data","pagination"],"additionalProperties":false}}}}}}},"/v1/courses/{courseId}":{"get":{"summary":"Get published course by ID","tags":["Courses"],"description":"Retrieve a single published course with its lessons and modules. Localized content in lesson and module data is stripped to only the master language. Returns 404 if the course does not exist or is not published.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"courseId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"courseId":{"type":"string","format":"uuid"},"insertedAt":{"type":"string"},"title":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"lessons":{"type":"array","items":{"type":"object","properties":{"lessonId":{"type":"string","format":"uuid"},"sortIndex":{"type":"number","nullable":true},"data":{},"modules":{"type":"array","items":{"type":"object","properties":{"moduleId":{"type":"string","format":"uuid"},"moduleType":{"type":"string"},"sortIndex":{"type":"number","nullable":true},"data":{}},"required":["moduleId","moduleType","sortIndex"],"additionalProperties":false}}},"required":["lessonId","sortIndex","modules"],"additionalProperties":false}}},"required":["courseId","insertedAt","title","description","lessons"],"additionalProperties":false}}}}}}},"/v1/courses/{courseId}/assignments":{"get":{"summary":"List course assignments","tags":["Course Assignments"],"description":"Retrieve a paginated list of user assignments for a course","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"in":"query","name":"pageSize","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"userId","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"courseId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"assignmentId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"courseId":{"type":"string","format":"uuid"},"startDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"dueDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"isFinished":{"type":"boolean"},"finishedAt":{"type":"string","nullable":true},"individualAssignment":{"type":"boolean"},"insertedAt":{"type":"string","nullable":true}},"required":["assignmentId","userId","courseId","startDate","dueDate","isFinished","finishedAt","individualAssignment","insertedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"number"},"pageSize":{"type":"number"},"total":{"type":"number"},"totalPages":{"type":"number"}},"required":["page","pageSize","total","totalPages"],"additionalProperties":false}},"required":["data","pagination"],"additionalProperties":false}}}}}},"post":{"summary":"Assign course to users","tags":["Course Assignments"],"description":"Enroll one or more users into a course","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"description":"User IDs to assign the course to"},"durationInDays":{"type":"integer","minimum":1,"nullable":true,"default":null,"description":"Number of days until due date (null = no due date)"},"individual":{"type":"boolean","default":false,"description":"Whether this is an individual assignment"},"reassign":{"type":"boolean","default":false,"description":"Whether to reassign if user already finished the course"}},"required":["userIds"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"courseId","required":true}],"security":[{"apiKey":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"],"additionalProperties":false}}}}}}},"/v1/courses/{courseId}/assignments/{assignmentId}":{"get":{"summary":"Get assignment by ID","tags":["Course Assignments"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"courseId","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"assignmentId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"assignmentId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"courseId":{"type":"string","format":"uuid"},"startDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"dueDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"isFinished":{"type":"boolean"},"finishedAt":{"type":"string","nullable":true},"individualAssignment":{"type":"boolean"},"insertedAt":{"type":"string","nullable":true}},"required":["assignmentId","userId","courseId","startDate","dueDate","isFinished","finishedAt","individualAssignment","insertedAt"],"additionalProperties":false}}}}}},"patch":{"summary":"Update assignment","tags":["Course Assignments"],"description":"Update the start date or due date of an active (not yet completed) assignment. Returns 409 if the assignment is already finished.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"startDate":{"type":"string","description":"Format: ISO 8601 date (YYYY-MM-DD)"},"dueDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"courseId","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"assignmentId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"assignmentId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"courseId":{"type":"string","format":"uuid"},"startDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"dueDate":{"type":"string","nullable":true,"description":"Format: ISO 8601 date (YYYY-MM-DD)"},"isFinished":{"type":"boolean"},"finishedAt":{"type":"string","nullable":true},"individualAssignment":{"type":"boolean"},"insertedAt":{"type":"string","nullable":true}},"required":["assignmentId","userId","courseId","startDate","dueDate","isFinished","finishedAt","individualAssignment","insertedAt"],"additionalProperties":false}}}}}},"delete":{"summary":"Delete assignment","tags":["Course Assignments"],"description":"Remove an active (not yet completed) course assignment. Returns 409 if the assignment is already finished. Completed assignments cannot be deleted to preserve certificate and audit data.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"courseId","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"assignmentId","required":true}],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Default Response"}}}}},"security":[{"apiKey":[]}]}