Skip to content

Capture — Interviews API

Base path: /api/v1/capture/interviews

See API Reference for auth, errors, and pagination.

This module covers three related resources:

  • Interview Templates — reusable, role-targeted question sets authored by admins and managers.
  • Interview Sessions — a live instance of a template assigned to an interviewee. Tracks the full lifecycle from creation through to knowledge extraction.
  • Shift Logs — supervisor end-of-shift structured notes captured as drafts and submitted to trigger knowledge extraction.

Plan: All endpoints require the Growth plan (interview_flow feature flag).

Roles:

Role Capabilities
member Read/act on own sessions and shift logs only
manager Full read access; can manage templates
admin Full read access; can manage templates

Interview Templates

Templates are org-scoped, role-targeted question sets. Each template holds an ordered array of question objects. Only managers and admins can create, update, or deactivate templates. All authenticated users on a Growth+ plan can read them.

Question object shape:

{
  "order": 1,
  "text": "Describe your main responsibilities in this role.",
  "category": "responsibilities",
  "follow_up_prompt": "Can you give a specific example from the past month?"
}
Field Type Required Constraints
order integer Yes >= 1; display order (1-based)
text string Yes 1–2000 characters
category string No max 100 characters; grouping tag
follow_up_prompt string No max 2000 characters

GET /templates

Auth: JWT required. Growth plan. All roles.

List interview templates for the caller's organisation. Admins and managers may pass include_inactive=true to receive deactivated templates. Members always receive only active templates.

Query parameters:

Param Type Default Description
include_inactive boolean string false Include deactivated templates. Admin/manager only.

Response 200 OK — array of template objects (not paginated):

[
  {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "org_id": "1a2b3c4d-0000-0000-0000-000000000001",
    "name": "Engineering On-boarding Interview",
    "description": "Standard Q&A for new engineers joining any team.",
    "role_target": "engineer",
    "questions": [
      {
        "order": 1,
        "text": "Describe your main responsibilities in your previous role.",
        "category": "experience",
        "follow_up_prompt": "Can you give a concrete example?"
      },
      {
        "order": 2,
        "text": "What tools and languages do you use daily?",
        "category": "technical",
        "follow_up_prompt": null
      }
    ],
    "created_by": "7f000000-0000-0000-0000-000000000002",
    "is_active": true,
    "created_at": "2026-01-15T09:00:00Z",
    "updated_at": "2026-03-10T14:30:00Z"
  }
]

Errors:

Code HTTP Cause
PLAN_UPGRADE_REQUIRED 403 Organisation below Growth plan
SUBSCRIPTION_REQUIRED 402 Subscription inactive or trial expired
curl -X GET "https://api.knora.io/api/v1/capture/interviews/templates" \
  -H "Authorization: Bearer <token>"

POST /templates

Auth: JWT required. Growth plan. manager or admin role.

Create a new interview template.

Request body:

Field Type Required Constraints
name string Yes 1–255 characters
description string No max 5000 characters
role_target string No max 100 characters (e.g. "engineer", "manager")
questions array of question objects Yes minimum 1 item
{
  "name": "Engineering On-boarding Interview",
  "description": "Standard Q&A for new engineers joining any team.",
  "role_target": "engineer",
  "questions": [
    {
      "order": 1,
      "text": "Describe your main responsibilities in your previous role.",
      "category": "experience",
      "follow_up_prompt": "Can you give a concrete example?"
    },
    {
      "order": 2,
      "text": "What tools and languages do you use daily?",
      "category": "technical",
      "follow_up_prompt": null
    }
  ]
}

Response 201 Created — newly created template object (same shape as GET /templates items).

Errors:

Code HTTP Cause
VALIDATION_ERROR 400 Missing required fields, constraint violations, or malformed question objects
PLAN_UPGRADE_REQUIRED 403 Organisation below Growth plan
UNAUTHORIZED 403 Caller is not a manager or admin
curl -X POST "https://api.knora.io/api/v1/capture/interviews/templates" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Engineering On-boarding Interview",
    "role_target": "engineer",
    "questions": [
      { "order": 1, "text": "Describe your main responsibilities.", "category": "experience" }
    ]
  }'

GET /templates/{template_id}

Auth: JWT required. Growth plan. All roles.

Fetch a single interview template by ID.

Path parameters:

Param Type Description
template_id UUID ID of the template

Response 200 OK — single template object (same shape as list items).

Errors:

Code HTTP Cause
INTERVIEW_TEMPLATE_NOT_FOUND 404 Template does not exist or belongs to a different org
PLAN_UPGRADE_REQUIRED 403 Organisation below Growth plan
curl -X GET "https://api.knora.io/api/v1/capture/interviews/templates/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer <token>"

PUT /templates/{template_id}

Auth: JWT required. Growth plan. manager or admin role.

Update an existing template. All fields are optional; send only what needs to change. Sending questions replaces the entire array.

Path parameters:

Param Type Description
template_id UUID ID of the template to update

Request body (all fields optional):

Field Type Constraints
name string 1–255 characters
description string max 5000 characters
role_target string max 100 characters
questions array of question objects Replaces the entire questions array
is_active boolean Set to false to deactivate without using the DELETE endpoint
{
  "name": "Updated Engineering Interview v2",
  "is_active": true,
  "questions": [
    {
      "order": 1,
      "text": "Walk us through your last project end-to-end.",
      "category": "experience"
    }
  ]
}

Response 200 OK — updated template object.

Errors:

Code HTTP Cause
VALIDATION_ERROR 400 Constraint violations
INTERVIEW_TEMPLATE_NOT_FOUND 404 Template not found in org
UNAUTHORIZED 403 Caller is not a manager or admin

DELETE /templates/{template_id}

Auth: JWT required. Growth plan. manager or admin role.

Soft-delete (deactivate) a template. The template is not removed from the database; existing sessions referencing it remain intact.

Path parameters:

Param Type Description
template_id UUID ID of the template to deactivate

Response 200 OK:

{
  "message": "Template deactivated.",
  "template": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "is_active": false,
    "...": "..."
  }
}

Errors:

Code HTTP Cause
INTERVIEW_TEMPLATE_NOT_FOUND 404 Template not found in org
UNAUTHORIZED 403 Caller is not a manager or admin

Use PUT /templates/{id} with "is_active": true to reactivate. New sessions cannot be started against an inactive template (INTERVIEW_TEMPLATE_INACTIVE).

Interview Sessions

A session binds a template to a specific interviewee. The lifecycle is:

not_started → in_progress → completed
                          → cancelled

Answers are submitted individually per question during the in_progress state. Completing a session triggers asynchronous knowledge extraction.

Session status values:

Value Description
not_started Session created but the interview has not begun
in_progress At least one answer has been submitted
completed All answers submitted; knowledge extraction triggered
cancelled Session was explicitly cancelled

POST /sessions

Auth: JWT required. Growth plan. All roles.

Start a new interview session by assigning a template to an interviewee. Members may only start sessions for themselves (interviewee_id must match their own user ID). Managers and admins can start sessions for any user in the org.

Request body:

Field Type Required Description
template_id UUID Yes The template to use for this session
interviewee_id UUID Yes The user being interviewed
interviewer_id UUID No The user conducting the interview (nullable)
{
  "template_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "interviewee_id": "7f000000-0000-0000-0000-000000000010",
  "interviewer_id": "7f000000-0000-0000-0000-000000000020"
}

Response 201 Created — session object without answers (answers field is excluded):

{
  "id": "aaaaaaaa-0000-0000-0000-000000000001",
  "org_id": "1a2b3c4d-0000-0000-0000-000000000001",
  "template_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "interviewee_id": "7f000000-0000-0000-0000-000000000010",
  "interviewer_id": "7f000000-0000-0000-0000-000000000020",
  "status": "not_started",
  "started_at": null,
  "completed_at": null,
  "created_at": "2026-06-01T10:00:00Z",
  "updated_at": "2026-06-01T10:00:00Z",
  "template": { "...": "full template object" },
  "interviewee": { "id": "...", "name": "Alice Smith", "email": "alice@example.com" },
  "interviewer": { "id": "...", "name": "Bob Jones", "email": "bob@example.com" }
}

Errors:

Code HTTP Cause
VALIDATION_ERROR 400 Missing required fields or invalid UUID format
INTERVIEW_TEMPLATE_NOT_FOUND 404 Template not found in org
INTERVIEW_TEMPLATE_INACTIVE 400 Template is deactivated; cannot start a new session
CANNOT_START_SESSION_FOR_OTHER_USER 403 Member trying to start a session for a different user
curl -X POST "https://api.knora.io/api/v1/capture/interviews/sessions" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "interviewee_id": "7f000000-0000-0000-0000-000000000010"
  }'

GET /sessions

Auth: JWT required. Growth plan. All roles.

List interview sessions with filtering and pagination. Members see only sessions where they are the interviewee or interviewer. Managers and admins see all sessions in the org.

Query parameters:

Param Type Description
status string Filter by status: not_started, in_progress, completed, cancelled
interviewee_id UUID Filter by interviewee
template_id UUID Filter by template
page integer Page number (default: 1)
per_page integer Items per page (default: 20, max: 100)

Response 200 OK — paginated list; each item excludes the answers array:

{
  "items": [
    {
      "id": "aaaaaaaa-0000-0000-0000-000000000001",
      "org_id": "1a2b3c4d-0000-0000-0000-000000000001",
      "template_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "interviewee_id": "7f000000-0000-0000-0000-000000000010",
      "interviewer_id": null,
      "status": "in_progress",
      "started_at": "2026-06-01T10:05:00Z",
      "completed_at": null,
      "created_at": "2026-06-01T10:00:00Z",
      "updated_at": "2026-06-01T10:05:00Z",
      "template": { "...": "..." },
      "interviewee": { "id": "...", "name": "Alice Smith", "email": "alice@example.com" },
      "interviewer": null
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "total_pages": 1,
    "has_next": false,
    "has_prev": false
  }
}

Errors:

Code HTTP Cause
VALIDATION_ERROR 400 Invalid UUID or datetime query param

GET /sessions/{session_id}

Auth: JWT required. Growth plan. All roles.

Get full session detail including all submitted answers. Members may only access sessions they are a participant in (as interviewee or interviewer).

Path parameters:

Param Type Description
session_id UUID ID of the session

Response 200 OK — full session object with answers array included:

{
  "id": "aaaaaaaa-0000-0000-0000-000000000001",
  "org_id": "1a2b3c4d-0000-0000-0000-000000000001",
  "template_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "interviewee_id": "7f000000-0000-0000-0000-000000000010",
  "interviewer_id": null,
  "status": "in_progress",
  "started_at": "2026-06-01T10:05:00Z",
  "completed_at": null,
  "created_at": "2026-06-01T10:00:00Z",
  "updated_at": "2026-06-01T10:05:00Z",
  "template": { "...": "full template object" },
  "interviewee": { "id": "...", "name": "Alice Smith", "email": "alice@example.com" },
  "interviewer": null,
  "answers": [
    {
      "id": "bbbbbbbb-0000-0000-0000-000000000001",
      "session_id": "aaaaaaaa-0000-0000-0000-000000000001",
      "question_index": 0,
      "answer_text": "I led the infrastructure migration for three services.",
      "answer_type": "text",
      "audio_file_path": null,
      "created_at": "2026-06-01T10:05:30Z",
      "updated_at": "2026-06-01T10:05:30Z"
    }
  ]
}

Errors:

Code HTTP Cause
INTERVIEW_SESSION_NOT_FOUND 404 Session not found in org
SESSION_ACCESS_DENIED 403 Member trying to access a session they are not a participant in

POST /sessions/{session_id}/answers

Auth: JWT required. Growth plan. All roles (session participants) or manager/admin.

Submit an answer for one question in the session. Answers are keyed by zero-based question_index matching the template's questions array. Submitting an answer moves the session to in_progress if it was not_started.

Path parameters:

Param Type Description
session_id UUID ID of the session

Request body:

Field Type Required Constraints
question_index integer Yes >= 0; zero-based index into the template's questions array
answer_text string Yes min 1 character; for voice answers this is the transcription
answer_type string No "text" (default) or "voice"
audio_file_path string No Path to the raw audio file; max 1024 characters; voice answers only
{
  "question_index": 0,
  "answer_text": "I led the infrastructure migration for three services over six months.",
  "answer_type": "text"
}

Voice answer example:

{
  "question_index": 1,
  "answer_text": "We use Python, TypeScript, and Terraform day to day.",
  "answer_type": "voice",
  "audio_file_path": "/recordings/sessions/aaaaaaaa/q1.webm"
}

Response 201 Created:

{
  "id": "bbbbbbbb-0000-0000-0000-000000000001",
  "session_id": "aaaaaaaa-0000-0000-0000-000000000001",
  "question_index": 0,
  "answer_text": "I led the infrastructure migration for three services over six months.",
  "answer_type": "text",
  "audio_file_path": null,
  "created_at": "2026-06-01T10:05:30Z",
  "updated_at": "2026-06-01T10:05:30Z"
}

Errors:

Code HTTP Cause
VALIDATION_ERROR 400 Missing required fields or invalid answer_type value
QUESTION_INDEX_OUT_OF_RANGE 400 question_index exceeds the number of questions in the template
SESSION_ALREADY_COMPLETED 400 Session is already completed; no more answers accepted
SESSION_ALREADY_CANCELLED 400 Session has been cancelled
INTERVIEW_SESSION_NOT_FOUND 404 Session not found in org
SESSION_ACCESS_DENIED 403 Caller is not a session participant and not a manager/admin
curl -X POST "https://api.knora.io/api/v1/capture/interviews/sessions/aaaaaaaa-0000-0000-0000-000000000001/answers" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "question_index": 0,
    "answer_text": "I led the infrastructure migration for three services.",
    "answer_type": "text"
  }'

POST /sessions/{session_id}/complete

Auth: JWT required. Growth plan. All roles (own sessions) or manager/admin (any session).

Mark a session as completed and trigger asynchronous knowledge extraction. This is a terminal state; no further answers can be submitted after completion.

Path parameters:

Param Type Description
session_id UUID ID of the session to complete

Request body: None.

Response 200 OK — session object without answers (answers field is excluded); status is immediately "completed":

{
  "message": "Session completed. Knowledge extraction started.",
  "session": {
    "id": "aaaaaaaa-0000-0000-0000-000000000001",
    "status": "completed",
    "completed_at": "2026-06-01T11:00:00Z",
    "...": "..."
  }
}

Knowledge extraction runs asynchronously after the response is returned.

Errors:

Code HTTP Cause
SESSION_ALREADY_COMPLETED 400 Session is already in completed state
SESSION_ALREADY_CANCELLED 400 Session is cancelled and cannot be completed
INTERVIEW_SESSION_NOT_FOUND 404 Session not found in org
SESSION_ACCESS_DENIED 403 Caller lacks permission to complete this session
curl -X POST "https://api.knora.io/api/v1/capture/interviews/sessions/aaaaaaaa-0000-0000-0000-000000000001/complete" \
  -H "Authorization: Bearer <token>"

DELETE /sessions/{session_id}

Auth: JWT required. Growth plan. All roles (own sessions) or manager/admin (any session).

Cancel an interview session. This is a terminal state. Cancellation does not delete the session or its answers from the database. Knowledge extraction is not triggered.

Path parameters:

Param Type Description
session_id UUID ID of the session to cancel

Request body: None.

Response 200 OK — session object without answers (answers field is excluded):

{
  "message": "Session cancelled.",
  "session": {
    "id": "aaaaaaaa-0000-0000-0000-000000000001",
    "status": "cancelled",
    "...": "..."
  }
}

Errors:

Code HTTP Cause
SESSION_ALREADY_CANCELLED 400 Session is already cancelled
SESSION_ALREADY_COMPLETED 400 Completed sessions cannot be cancelled
INTERVIEW_SESSION_NOT_FOUND 404 Session not found in org
SESSION_ACCESS_DENIED 403 Caller lacks permission to cancel this session

Shift Logs

Shift logs capture supervisor end-of-shift notes in a structured form. They are created as draft and remain editable until explicitly submitted. Submission triggers asynchronous knowledge extraction.

Shift log status values:

Value Description
draft Log created but not yet submitted; editable
submitted Log submitted; knowledge extraction triggered; no further edits allowed

POST /shift-logs

Auth: JWT required. Growth plan. All roles.

Create a new supervisor shift log saved as draft. The user_id on the created log is always the authenticated caller; logs cannot be created on behalf of other users through this endpoint.

Request body:

Field Type Required Constraints
shift_date ISO-8601 datetime Yes Date and time of the shift
notes string Yes min 1 character; free-text supervisor notes
location string No max 255 characters
department_id UUID No UUID of the department
{
  "shift_date": "2026-06-01T22:00:00Z",
  "notes": "Quiet shift. Equipment check completed. One minor incident logged with security.",
  "location": "Warehouse A",
  "department_id": "cccccccc-0000-0000-0000-000000000001"
}

Response 201 Created:

{
  "id": "dddddddd-0000-0000-0000-000000000001",
  "org_id": "1a2b3c4d-0000-0000-0000-000000000001",
  "user_id": "7f000000-0000-0000-0000-000000000010",
  "template_id": null,
  "shift_date": "2026-06-01T22:00:00Z",
  "location": "Warehouse A",
  "department_id": "cccccccc-0000-0000-0000-000000000001",
  "notes": "Quiet shift. Equipment check completed. One minor incident logged with security.",
  "status": "draft",
  "submitted_at": null,
  "created_at": "2026-06-01T23:15:00Z",
  "updated_at": "2026-06-01T23:15:00Z",
  "user": { "id": "...", "name": "Carol Davies", "email": "carol@example.com" },
  "template": null,
  "department": { "...": "department object or null" }
}

Errors:

Code HTTP Cause
VALIDATION_ERROR 400 Missing required fields or invalid datetime format
curl -X POST "https://api.knora.io/api/v1/capture/interviews/shift-logs" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "shift_date": "2026-06-01T22:00:00Z",
    "notes": "Quiet shift. Equipment check completed.",
    "location": "Warehouse A"
  }'

GET /shift-logs

Auth: JWT required. Growth plan. All roles.

List shift logs with filtering and pagination. Members see only their own shift logs. Managers and admins see all logs in the org. The user_id filter is enforced at the service layer — a member passing a different user_id will still only receive their own logs.

Query parameters:

Param Type Description
user_id UUID Filter by author (admin/manager see any user; members are scoped to themselves regardless)
department_id UUID Filter by department
date_from ISO-8601 datetime Return logs with shift_date at or after this value
date_to ISO-8601 datetime Return logs with shift_date at or before this value
status string Filter by status: draft or submitted
page integer Page number (default: 1)
per_page integer Items per page (default: 20, max: 100)

Response 200 OK:

{
  "items": [
    {
      "id": "dddddddd-0000-0000-0000-000000000001",
      "org_id": "1a2b3c4d-0000-0000-0000-000000000001",
      "user_id": "7f000000-0000-0000-0000-000000000010",
      "template_id": null,
      "shift_date": "2026-06-01T22:00:00Z",
      "location": "Warehouse A",
      "department_id": "cccccccc-0000-0000-0000-000000000001",
      "notes": "Quiet shift. Equipment check completed.",
      "status": "draft",
      "submitted_at": null,
      "created_at": "2026-06-01T23:15:00Z",
      "updated_at": "2026-06-01T23:15:00Z",
      "user": { "id": "...", "name": "Carol Davies", "email": "carol@example.com" },
      "template": null,
      "department": null
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "total_pages": 1,
    "has_next": false,
    "has_prev": false
  }
}

Errors:

Code HTTP Cause
VALIDATION_ERROR 400 Invalid UUID or non-ISO-8601 datetime query param

GET /shift-logs/{log_id}

Auth: JWT required. Growth plan. All roles.

Fetch a single shift log by ID with full detail. Members may only access their own logs.

Path parameters:

Param Type Description
log_id UUID ID of the shift log

Response 200 OK — single shift log object (same shape as list items).

Errors:

Code HTTP Cause
SHIFT_LOG_NOT_FOUND 404 Log not found in org
SHIFT_LOG_ACCESS_DENIED 403 Member trying to access another user's log

PUT /shift-logs/{log_id}

Auth: JWT required. Growth plan. All roles (own draft logs).

Update a draft shift log. Submitted logs cannot be edited.

Path parameters:

Param Type Description
log_id UUID ID of the shift log

Request body (all fields optional):

Field Type Constraints
shift_date ISO-8601 datetime Replaces the shift date
notes string min 1 character
location string max 255 characters
department_id UUID Replaces the department association
{
  "notes": "Updated notes: also completed handover with night shift supervisor.",
  "location": "Warehouse B"
}

Response 200 OK — updated shift log object.

Errors:

Code HTTP Cause
VALIDATION_ERROR 400 Constraint violations (e.g. empty notes)
SHIFT_LOG_ALREADY_SUBMITTED 400 Log is already submitted; edits are not allowed
SHIFT_LOG_NOT_FOUND 404 Log not found in org
SHIFT_LOG_ACCESS_DENIED 403 Caller does not own the log (and is not a manager/admin)
curl -X PUT "https://api.knora.io/api/v1/capture/interviews/shift-logs/dddddddd-0000-0000-0000-000000000001" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "notes": "Updated notes: also completed handover with night shift supervisor."
  }'

POST /shift-logs/{log_id}/submit

Auth: JWT required. Growth plan. All roles (own logs) or manager/admin (any log).

Submit a draft shift log. Transitions it from draft to submitted and triggers asynchronous knowledge extraction. Once submitted, the log cannot be edited. submitted_at is set to the server timestamp at submission time.

Path parameters:

Param Type Description
log_id UUID ID of the shift log to submit

Request body: None.

Response 200 OK:

{
  "message": "Shift log submitted. Knowledge extraction started.",
  "shift_log": {
    "id": "dddddddd-0000-0000-0000-000000000001",
    "status": "submitted",
    "submitted_at": "2026-06-01T23:30:00Z",
    "...": "..."
  }
}

Errors:

Code HTTP Cause
SHIFT_LOG_ALREADY_SUBMITTED 400 Log has already been submitted
SHIFT_LOG_NOT_FOUND 404 Log not found in org
SHIFT_LOG_ACCESS_DENIED 403 Caller lacks permission to submit this log
curl -X POST "https://api.knora.io/api/v1/capture/interviews/shift-logs/dddddddd-0000-0000-0000-000000000001/submit" \
  -H "Authorization: Bearer <token>"

Error Code Reference

Code HTTP Module Description
VALIDATION_ERROR 400 All Request body or query param failed schema validation
INTERVIEW_TEMPLATE_NOT_FOUND 404 Templates Template does not exist in the org
INTERVIEW_TEMPLATE_INACTIVE 400 Sessions Attempted to start a session with a deactivated template
INTERVIEW_SESSION_NOT_FOUND 404 Sessions Session does not exist in the org
SESSION_ALREADY_COMPLETED 400 Sessions Operation invalid on a completed session
SESSION_ALREADY_CANCELLED 400 Sessions Operation invalid on a cancelled session
QUESTION_INDEX_OUT_OF_RANGE 400 Sessions question_index exceeds the template's questions array length
SESSION_ACCESS_DENIED 403 Sessions Member accessing a session they are not a participant in
CANNOT_START_SESSION_FOR_OTHER_USER 403 Sessions Member setting interviewee_id to a different user
SHIFT_LOG_NOT_FOUND 404 Shift Logs Shift log does not exist in the org
SHIFT_LOG_ALREADY_SUBMITTED 400 Shift Logs Attempted edit or re-submission of a submitted log
SHIFT_LOG_ACCESS_DENIED 403 Shift Logs Member accessing another user's log
PLAN_UPGRADE_REQUIRED 403 All Organisation plan is below Growth
SUBSCRIPTION_REQUIRED 402 All Subscription is inactive or trial has expired
MISSING_ORG_CLAIM 403 All JWT does not contain an org_id claim
INVALID_ORG_CLAIM 403 All JWT org_id claim is not a valid UUID
ORG_NOT_FOUND 403 All Organisation referenced in JWT no longer exists