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¶
- Create transaction:
POST /api/v3/ai/transaction/start/ - Make changes with header:
X-AI-Transaction-ID: tx_abc123 - Propose transaction:
POST /api/v3/ai/transaction/tx_abc123/propose/ - 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 theX-Request-IDheader) and a_field_infomap describing the response's fields inline. List endpoints wrap rows as{"results": [...]}. Errors use{"error": {"code", "message", "details", "hint", "request_id"}}— readhintfor remediation guidance.
Clinicians¶
GET /api/v3/ai/clinicians/- List clinicians (filter: active, group)GET /api/v3/ai/clinicians/{id}/- Retrieve one clinicianPOST /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 termPOST /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 ausageobject 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 pagePOST /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 (optionalnote, max 500 chars, visible on calendar/ICS)GET /api/v3/ai/leave/{clinician_id}/quota/- Remaining leave quota for clinicianPOST /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 requestPOST /api/v3/ai/leave/requests/{leave_request_id}/approve/- Approve a leave requestPOST /api/v3/ai/leave/requests/{leave_request_id}/cancel/- Cancel a leave requestPOST /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 requestsGET /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 underresults[])POST /api/v3/ai/transaction/start/- Create a new transactionGET /api/v3/ai/transaction/{id}/- Retrieve transaction detailsPOST /api/v3/ai/transaction/{id}/propose/- Propose transaction for approvalPOST /api/v3/ai/transaction/{id}/unpropose/- Return a PROPOSED transaction to PENDING (409CONFLICTif no longer PROPOSED)POST /api/v3/ai/transaction/{id}/cancel/- Cancel one transaction, discarding staged changesPOST /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 underresults[])POST /api/v3/ai/shifts/- Create a new shiftGET /api/v3/ai/shifts/{id}/- Retrieve shift detailsPATCH /api/v3/ai/shifts/{id}/- Stage an update to an existing shiftGET /api/v3/ai/shifts/staged/- List shifts staged in the active transactionPOST /api/v3/ai/shifts/delete-bulk/- Stage bulk deletion of shifts in a date rangePOST /api/v3/ai/shifts/generate-rota/- Run Phase 5 generation into staging
Rota Generation¶
GET /api/v3/ai/rota-generation/steps/- List available generation phasesPOST /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.