Skip to content

AI API Reference

Business rules are auto-generated from /api/v3/ai/schema/rules/ This document provides additional context not captured in code

Overview

The AI Agent API allows external AI systems to interact with the rota management system. All write operations require browser-based approval before committing to the database.

Authentication

Include header: Authorization: Bearer <api_key>

Transaction Flow

  1. Create transaction: POST /api/v3/ai/transaction/start/
  2. Make changes with header: X-AI-Transaction-ID: tx_abc123
  3. Propose transaction: POST /api/v3/ai/transaction/tx_abc123/propose/
  4. User approves via browser: /admin/ai-approvals/tx_abc123

Why These Rules Exist

Staffing Minimums

  • Ensures safe clinical coverage
  • Based on historical demand patterns
  • Lower on weekends (elective work only)
  • Higher post-bank-holiday (catch-up demand)

Fairness Objectives

  • Partners deserve equal distribution of undesirable shifts
  • Mondays are disproportionately unpopular
  • WTE adjustment ensures part-time partners aren't over-scheduled

Pinned Shifts

Constraint Validation

All shift creations are validated against Phase 5 hard constraints:

H2: Leave Conflicts - Cannot create shifts during approved leave periods

H3: Cannot-Work Days - Respects clinician's cannot_work_days from their working term - Example: Justin cannot work Wednesdays per his working term

H4b: DUTY Conflicts - Cannot create STANDARD shifts when clinician already has DUTY that day

Other Validations: - Date must be in the future - Clinician must have an active working term

Constraint Overrides: If override_constraints: true is set, validation violations are recorded but don't block creation. These shifts are flagged on the approval page and always require manual review.

Override Response Example:

{
  "id": 1,
  "clinician": 4,
  "clinician_name": "Justin Tankard",
  "date": "2026-05-27",
  "type": "STANDARD",
  "constraint_overrides": ["CANNOT_WORK_DAY"]
}

Pinned Shifts

  • Manual overrides for personal commitments
  • Clinicians may have childcare, medical appointments, etc.
  • Overuse breaks optimization (pin sparingly)

Available Endpoints

Response envelope (all endpoints): every success response carries a request_id (also sent as the X-Request-ID header) and a _field_info map describing the response's fields inline. List endpoints wrap rows as {"results": [...]}. Errors use {"error": {"code", "message", "details", "hint", "request_id"}} — read hint for remediation guidance.

Clinicians

  • GET /api/v3/ai/clinicians/ - List clinicians (filter: active, group)
  • GET /api/v3/ai/clinicians/{id}/ - Retrieve one clinician
  • POST /api/v3/ai/clinicians/ - Create (supports ?preview=true)
  • PATCH /api/v3/ai/clinicians/{id}/ - Update (supports ?preview=true)
  • POST /api/v3/ai/clinicians/{id}/rollback/ - Revert last AI mutation within 7 days

Working Terms

  • GET /api/v3/ai/working-terms/ - List terms (filter: clinician_id, active_on)
  • GET /api/v3/ai/working-terms/{id}/ - Retrieve one term
  • POST /api/v3/ai/working-terms/ - Create (supports ?preview=true)
  • PATCH /api/v3/ai/working-terms/{id}/ - Update (supports ?preview=true)
  • GET /api/v3/ai/working-terms/{id}/calculate-leave-entitlement/ - Derive a salaried doctor's annual leave entitlement — annual leave + NHS days + the net sessional bank holiday days ((sessions/10) per bank holiday in the term, less one per bank holiday on a working day, never negative) — plus a usage object reporting the leave booked against the term (approved, pending, remaining vs both the derived and stored figures); override: sessions, start_date, end_date; same backend as the admin Leave Calculator page
  • POST /api/v3/ai/working-terms/{id}/calculate-leave-entitlement/?persist=true - Same calculation, persisting the rounded figure to the term's entitlement (write key; audited and rollable)
  • POST /api/v3/ai/working-terms/{id}/rollback/ - Revert last AI mutation within 7 days

Leave

  • GET /api/v3/ai/leave/ - List leave requests (filter: clinician_id, status, date range)
  • GET /api/v3/ai/leave/{id}/ - Retrieve a leave request (with action URLs)
  • POST /api/v3/ai/leave/create/ - Create a leave request (optional note, max 500 chars, visible on calendar/ICS)
  • GET /api/v3/ai/leave/{clinician_id}/quota/ - Remaining leave quota for clinician
  • POST /api/v3/ai/leave/validate/ - Pre-flight validate a leave request (with staffing impact and policy decision)
  • POST /api/v3/ai/leave/validate-weekly/ - Validate leave by week number (with staffing impact and policy decision)
  • POST /api/v3/ai/leave/validate-approval/{leave_request_id}/ - Re-validate an existing leave request
  • POST /api/v3/ai/leave/requests/{leave_request_id}/approve/ - Approve a leave request
  • POST /api/v3/ai/leave/requests/{leave_request_id}/cancel/ - Cancel a leave request
  • POST /api/v3/ai/leave/requests/{leave_request_id}/note/ - Set or clear the public note on a leave request (any status; audited)
  • GET /api/v3/ai/leave/cancellation-requests/ - List pending/approved leave cancellation requests
  • GET /api/v3/ai/leave/{leave_id}/cancellation-request/ - Retrieve the cancellation request for a specific leave request

Transactions

  • GET /api/v3/ai/transaction/ - List all transactions (rows under results[])
  • POST /api/v3/ai/transaction/start/ - Create a new transaction
  • GET /api/v3/ai/transaction/{id}/ - Retrieve transaction details
  • POST /api/v3/ai/transaction/{id}/propose/ - Propose transaction for approval
  • POST /api/v3/ai/transaction/{id}/unpropose/ - Return a PROPOSED transaction to PENDING (409 CONFLICT if no longer PROPOSED)
  • POST /api/v3/ai/transaction/{id}/cancel/ - Cancel one transaction, discarding staged changes
  • POST /api/v3/ai/transaction/cancel-all/ - Cancel all non-terminal transactions for the key

Shifts

  • GET /api/v3/ai/shifts/ - List all shifts (supports filtering; rows under results[])
  • POST /api/v3/ai/shifts/ - Create a new shift
  • GET /api/v3/ai/shifts/{id}/ - Retrieve shift details
  • PATCH /api/v3/ai/shifts/{id}/ - Stage an update to an existing shift
  • GET /api/v3/ai/shifts/staged/ - List shifts staged in the active transaction
  • POST /api/v3/ai/shifts/delete-bulk/ - Stage bulk deletion of shifts in a date range
  • POST /api/v3/ai/shifts/generate-rota/ - Run Phase 5 generation into staging

Rota Generation

  • GET /api/v3/ai/rota-generation/steps/ - List available generation phases
  • POST /api/v3/ai/rota-generation/generate-phase/ - Run one phase (1-6 or "all") into staging

Shift Creation Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | clinician | integer | Yes | Clinician ID | | date | date (YYYY-MM-DD) | Yes | Shift date (must be future) | | type | string | No | Shift type (default: STANDARD) | | duration | string | No | Duration (default: FULL) | | override_constraints | boolean | No | Bypass validation constraints (default: false) |

Shift Filtering: | Parameter | Type | Example | Description | |-----------|------|---------|-------------| | date_from | date (YYYY-MM-DD) | ?date_from=2026-01-05 | Only shifts on or after this date | | date_to | date (YYYY-MM-DD) | ?date_to=2026-01-11 | Only shifts on or before this date | | clinician | integer | ?clinician=3 | Only shifts for clinician ID | | clinician_name | string | ?clinician_name=Victoria | Partial name match (case-insensitive) | | type | string | ?type=DUTY | Shift type: STANDARD, DUTY, STUDY_LEAVE, CORONERS | | status | string | ?status=SCHEDULED | Shift status: SCHEDULED, COMPLETED, CANCELLED | | is_pinned | boolean | ?is_pinned=true | Filter by pinned status |

Examples: - GET /api/v3/ai/shifts/?date_from=2026-01-05&date_to=2026-01-11 - Next week's shifts - GET /api/v3/ai/shifts/?clinician_name=Victoria&type=DUTY - Victoria's duty shifts - GET /api/v3/ai/shifts/?status=SCHEDULED&is_pinned=false - Unpinned scheduled shifts

Response rows are under results[] (unified v3 envelope). Results ordered by date, then clinician_name.

Staged Shifts

  • GET /api/v3/ai/shifts/staged/ - List shifts staged in the active transaction

Returns the ShiftStaging records created within the current PENDING transaction (via POST /shifts/, POST /shifts/delete-bulk/, or POST /shifts/generate-rota/). Lets the agent inspect what has been staged before calling /transaction/{id}/propose/.

Requires the X-AI-Transaction-ID header (or a single active PENDING transaction for the API key). Returns 403 TRANSACTION_REQUIRED if no active transaction.

Staged Shift Filtering: | Parameter | Type | Example | Description | |-----------|------|---------|-------------| | date_from | date (YYYY-MM-DD) | ?date_from=2026-01-05 | Only staged shifts on or after this date | | date_to | date (YYYY-MM-DD) | ?date_to=2026-01-11 | Only staged shifts on or before this date | | clinician | integer | ?clinician=3 | Only staged shifts for clinician ID | | clinician_name | string | ?clinician_name=Victoria | Partial name match (case-insensitive) | | type | string | ?type=DUTY | Shift type: STANDARD, DUTY, STUDY_LEAVE, CORONERS | | status | string | ?status=SCHEDULED | Shift status: SCHEDULED, COMPLETED, CANCELLED | | is_pinned | boolean | ?is_pinned=true | Filter by pinned status | | is_deletion | boolean | ?is_deletion=true | Filter by deletion flag (additions vs deletions) |

Response fields: Each entry includes id, clinician, clinician_name, date, type, duration, status, is_pinned, is_off_sick, is_locum_booking, is_deletion, constraint_overrides, created_at, modified_at.

Results ordered by date, then clinician_name.

Reports

  • GET /api/v3/ai/reports/ - List WTE / remaining-leave reports (filter: clinician_id, date range)

Audit

  • GET /api/v3/ai/audit/ - List audit-log entries (filter: clinician_id, since/until date range)

Alerts

  • GET /api/v3/ai/alerts/ - List staffing alerts (filter: clinician_id, date range, resolved status)

Validation

  • POST /api/v3/ai/validation/staffing/ - Pre-flight staffing-impact check for a proposed leave request

Config

  • GET /api/v3/ai/config/ - Retrieve the current SystemConfiguration (fixed period, WTE defaults, AI API flags, etc.)

Schema

  • GET /api/v3/ai/schema/rules/ - Get business rules schema

Implementation Notes

The endpoint surface above is generated live by ai_api/v3/urls.py; consult that file (or the schema/rules/ endpoint) for the authoritative list. OpenAPI field descriptions are injected into every response via _field_info and the drf-spectacular schema.