Work Order QMS Module — API Endpoint Specification
Classification: Internal — Engineering
Date: 2026-02-13
Artifact: 71 of WO System Series
Status: Proposed
Source Artifacts: 13-tdd.md §1.1, 16-prisma-data-model.md, 22-rbac-permissions-matrix.md, 67-integration-api-strategy.md
1. API Conventions
1.1 Base URL & Versioning
Production: https://api.coditect.io/v1
Staging: https://api-staging.coditect.io/v1
Development: http://localhost:3000/v1
Versioning: URL path (/v1/, /v2/)
Current: v1 (GA)
Sunset: None (first version)
1.2 Authentication
All endpoints require authentication via one of:
| Method | Header | Use Case | Token Lifetime |
|---|---|---|---|
| Bearer JWT | Authorization: Bearer <token> | Human users (browser/mobile) | 1 hour (refresh: 7 days) |
| Service API Key | X-API-Key: <key> | Service-to-service integrations | 90-day rotation |
| Agent Token | Authorization: Bearer <agent-token> | CODITECT agent execution | Per-execution (ephemeral) |
All tokens carry tenant_id claim. PostgreSQL RLS enforces tenant isolation regardless of application logic.
1.3 Standard Headers
| Header | Direction | Required | Description |
|---|---|---|---|
Authorization | Request | Yes | Bearer token or API key |
Content-Type | Request | Yes (POST/PUT/PATCH) | application/json |
X-Request-ID | Request | Recommended | Idempotency key (UUID v7) — prevents duplicate operations |
X-Tenant-ID | Request | No (derived from token) | Override for super-admin operations only |
X-Correlation-ID | Response | Always | Trace ID for observability — include in support tickets |
X-RateLimit-Remaining | Response | Always | Remaining requests in current window |
X-RateLimit-Reset | Response | Always | Unix timestamp when window resets |
Sunset | Response | Conditional | ISO 8601 date when endpoint will be removed |
1.4 Pagination
All list endpoints use cursor-based pagination:
{
"data": [...],
"pagination": {
"cursor": "eyJpZCI6ImNsdTEyMzQ1Njc4OTAifQ==",
"has_more": true,
"total_count": 1247
}
}
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
limit | integer | 25 | 100 | Items per page |
cursor | string | null | — | Opaque cursor from previous response |
sort | string | created_at:desc | — | Field and direction (field:asc or field:desc) |
1.5 Error Response Format
All errors follow RFC 7807 (Problem Details):
{
"type": "https://docs.coditect.io/errors/validation-failed",
"title": "Validation Failed",
"status": 422,
"detail": "Work order cannot transition from DRAFT to IN_PROGRESS without approval.",
"instance": "/v1/work-orders/clu12345/status",
"correlation_id": "01HRX7QBPK4N8JMZV3Y5K2DWTF",
"errors": [
{
"field": "status",
"code": "INVALID_TRANSITION",
"message": "Transition DRAFT→IN_PROGRESS is not permitted; required: DRAFT→PENDING_APPROVAL"
}
],
"timestamp": "2026-02-13T14:30:00.000Z"
}
1.6 Error Code Catalog
| HTTP Status | Error Type | Code | Description | Retry |
|---|---|---|---|---|
| 400 | Bad Request | INVALID_INPUT | Malformed JSON or missing required field | No |
| 400 | Bad Request | INVALID_TRANSITION | State machine transition not permitted | No |
| 401 | Unauthorized | TOKEN_EXPIRED | JWT expired | Yes (refresh) |
| 401 | Unauthorized | TOKEN_INVALID | Token signature invalid or revoked | No (re-auth) |
| 403 | Forbidden | PERMISSION_DENIED | Authenticated but insufficient permissions | No |
| 403 | Forbidden | SOD_VIOLATION | Separation of Duties conflict | No |
| 403 | Forbidden | TENANT_MISMATCH | Resource belongs to different tenant | No |
| 404 | Not Found | RESOURCE_NOT_FOUND | Entity does not exist or is not visible to caller | No |
| 409 | Conflict | VERSION_CONFLICT | Optimistic concurrency violation | Yes (re-fetch) |
| 409 | Conflict | DUPLICATE_OPERATION | Idempotency key collision (same request already processed) | No (use existing) |
| 422 | Unprocessable | VALIDATION_FAILED | Business rule validation failure | No |
| 422 | Unprocessable | GUARD_REJECTED | State machine guard condition not met | No (fix condition) |
| 422 | Unprocessable | DEPENDENCY_UNSATISFIED | Linked WO dependency not complete | No (wait) |
| 429 | Rate Limited | RATE_EXCEEDED | Too many requests | Yes (after reset) |
| 500 | Internal | INTERNAL_ERROR | Unhandled server error | Yes (with backoff) |
| 503 | Unavailable | SERVICE_DEGRADED | Upstream dependency unavailable | Yes (with backoff) |
1.7 Rate Limits
| Tier | Read (GET) | Write (POST/PATCH/PUT) | Audit Export | Window |
|---|---|---|---|---|
| Starter | 100/min | 30/min | 5/hour | Rolling |
| Professional | 500/min | 100/min | 20/hour | Rolling |
| Enterprise | 2,000/min | 500/min | Unlimited | Rolling |
| Agent (internal) | 5,000/min | 1,000/min | N/A | Rolling |
2. Work Order Endpoints
2.1 Create Work Order
POST /v1/work-orders
Authorization: wo:create permission (ORIGINATOR, ASSIGNER, SYSTEM_OWNER)
Request Body:
{
"type": "CORRECTIVE" | "PREVENTIVE" | "CALIBRATION" | "INSTALLATION" | "UPGRADE" | "DECOMMISSION",
"regulatory": true,
"priority": "LOW" | "MEDIUM" | "HIGH" | "CRITICAL",
"title": "HPLC-001 Annual PM and Calibration",
"description": "Perform annual preventive maintenance...",
"assetId": "asset_clu123",
"masterId": null,
"dependsOn": [],
"scheduledStart": "2026-03-15T09:00:00Z",
"scheduledEnd": "2026-03-15T17:00:00Z",
"metadata": {}
}
| Field | Type | Required | Validation |
|---|---|---|---|
type | enum | Yes | One of 6 WO types |
regulatory | boolean | Yes | If true, requires QA approval chain |
priority | enum | Yes | One of 4 priority levels |
title | string | Yes | 5–500 chars |
description | string | No | Max 10,000 chars |
assetId | string | No | Must exist in asset registry if provided |
masterId | string | No | If set, creates a linked WO under this master |
dependsOn | string[] | No | WO IDs that must complete before this WO starts |
scheduledStart | datetime | No | ISO 8601; must be future |
scheduledEnd | datetime | No | Must be after scheduledStart |
Response (201 Created):
{
"data": {
"id": "wo_clu789",
"status": "DRAFT",
"type": "PREVENTIVE",
"regulatory": true,
"priority": "HIGH",
"title": "HPLC-001 Annual PM and Calibration",
"description": "...",
"assetId": "asset_clu123",
"masterId": null,
"dependsOn": [],
"scheduledStart": "2026-03-15T09:00:00Z",
"scheduledEnd": "2026-03-15T17:00:00Z",
"createdBy": "user_abc",
"createdAt": "2026-02-13T14:30:00Z",
"updatedAt": "2026-02-13T14:30:00Z",
"version": 1,
"metadata": {}
}
}
Audit: Creates AuditTrail entry: {action: "CREATE", entity_type: "WorkOrder", entity_id: "wo_clu789"}.
Compliance: If regulatory: true, compliance engine validates required fields and pre-populates approval chain template.
2.2 Get Work Order
GET /v1/work-orders/:id
Authorization: wo:read per RBAC matrix (role + ownership determines field visibility)
Response (200 OK):
Full WO object (same shape as create response) plus computed fields:
{
"data": {
"...": "all creation fields",
"assigneeId": "user_def",
"assigneeName": "Jane Smith",
"completedAt": null,
"closedAt": null,
"approvals": [
{
"id": "apr_001",
"approverId": "user_ghi",
"role": "SYSTEM_OWNER",
"status": "APPROVED",
"decidedAt": "2026-02-13T15:00:00Z",
"signatureId": "sig_xyz"
}
],
"linkedWorkOrders": 3,
"progress": {
"total": 5,
"completed": 2,
"blocked": 1,
"percentComplete": 40
},
"riskAssessment": {
"riskScore": 12,
"likelihood": 3,
"impact": 4,
"category": "COMPLIANCE"
}
}
}
VENDOR role: Receives filtered view — no riskAssessment, limited approvals, no internal metadata.
2.3 List Work Orders
GET /v1/work-orders?status=IN_PROGRESS&priority=HIGH®ulatory=true&limit=25&cursor=xxx
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status | enum (comma-separated) | Filter by status(es) |
type | enum (comma-separated) | Filter by WO type(s) |
priority | enum (comma-separated) | Filter by priority(ies) |
regulatory | boolean | Filter regulatory/non-regulatory |
assetId | string | Filter by asset |
masterId | string | Filter linked WOs under a master |
assigneeId | string | Filter by assignee |
createdAfter | datetime | Created after this timestamp |
createdBefore | datetime | Created before this timestamp |
search | string | Full-text search on title + description |
Authorization: Results filtered by RBAC. VENDOR sees only WOs assigned to their entity. AUDITOR sees all WOs read-only.
2.4 Transition Status
PATCH /v1/work-orders/:id/status
Authorization: Transition-specific per state machine guard (19-state-machine-with-guards.md)
Request Body:
{
"targetStatus": "PENDING_APPROVAL",
"reason": "Job plan complete, ready for SO review",
"version": 3
}
| Field | Type | Required | Validation |
|---|---|---|---|
targetStatus | enum | Yes | Must be valid transition from current status |
reason | string | Conditional | Required if regulatory: true |
version | integer | Yes | Optimistic concurrency — must match current version |
Response (200 OK): Updated WO with new status and incremented version.
Error Responses:
409 VERSION_CONFLICTifversiondoesn't match (another user modified the WO)422 INVALID_TRANSITIONif state machine rejects the transition422 GUARD_REJECTEDif a guard condition fails (e.g., missing approval for regulatory WO)403 SOD_VIOLATIONif approver is same as originator
Guards Evaluated (examples):
DRAFT→PENDING_APPROVAL: Job plan exists, required fields populatedPENDING_APPROVAL→ASSIGNED: All required approvals collected, e-signatures validIN_PROGRESS→COMPLETED: All linked WOs completed or explicitly waivedCOMPLETED→CLOSED: Final documentation attached, compliance engine sign-off
Audit: Immutable audit entry with previous_value (old status) and new_value (new status), plus reason and performer identity.
2.5 Update Work Order Fields
PUT /v1/work-orders/:id
Authorization: wo:update — varies by status (DRAFT: broad; post-DRAFT: restricted fields only)
Mutable Fields by Status:
| Status | Mutable Fields |
|---|---|
| DRAFT | All fields except id, tenantId, createdBy, createdAt |
| PLANNED, PENDING_APPROVAL | priority, scheduledStart, scheduledEnd, description, metadata |
| ASSIGNED, IN_PROGRESS | priority (with re-approval if regulatory), metadata |
| BLOCKED | metadata (block reason, unblock plan) |
| COMPLETED, CLOSED | None (immutable) |
Request requires version field for optimistic concurrency.
3. Approval Endpoints
3.1 Request Approval
POST /v1/work-orders/:id/approvals
Request:
{
"approverId": "user_ghi",
"role": "SYSTEM_OWNER",
"dueDate": "2026-02-15T17:00:00Z"
}
3.2 Submit Approval Decision
PATCH /v1/work-orders/:id/approvals/:approvalId
Request:
{
"decision": "APPROVED" | "REJECTED" | "RETURNED_FOR_REVISION",
"comments": "Approved. Job plan adequate for HPLC-001 annual PM.",
"signature": {
"authMethod": "PASSWORD_REAUTH",
"meaning": "Approval of Work Order wo_clu789 as System Owner"
}
}
Compliance: If regulatory: true, signature block is required. Triggers re-authentication flow (64-security-architecture.md §2.3). Creates ElectronicSignature record with cryptographic hash binding (17-e-signature-architecture.md).
SOD Enforcement: Server rejects if approverId matches createdBy for same WO (22-rbac-permissions-matrix.md §5.1).
3.3 List Approvals
GET /v1/work-orders/:id/approvals
Returns all approval records for the WO including pending, approved, rejected, with signature verification status.
4. Job Plan Endpoints
4.1 Create/Update Job Plan
POST /v1/work-orders/:id/job-plan
Request:
{
"steps": [
{
"sequence": 1,
"description": "Power down HPLC system",
"estimatedMinutes": 15,
"toolRequirements": ["tool_wrench_set", "tool_multimeter"],
"experienceRequirements": ["exp_hplc_maintenance"],
"personCount": 1
}
],
"materialRequirements": [
{"materialId": "mat_filter_001", "quantity": 2, "unit": "EACH"}
],
"estimatedTotalHours": 8.0,
"specialInstructions": "Requires cleanroom access"
}
4.2 Get Job Plan
GET /v1/work-orders/:id/job-plan
5. Hierarchy & Dependency Endpoints
5.1 List Linked Work Orders
GET /v1/work-orders/:id/linked?include_progress=true
Returns all WOs linked to a master, with optional progress summaries.
5.2 Get Dependency Graph
GET /v1/work-orders/:id/dependency-graph
Response:
{
"data": {
"nodes": [
{"id": "wo_001", "status": "COMPLETED", "title": "..."},
{"id": "wo_002", "status": "IN_PROGRESS", "title": "..."},
{"id": "wo_003", "status": "DRAFT", "title": "...", "blockedBy": ["wo_002"]}
],
"edges": [
{"from": "wo_001", "to": "wo_002"},
{"from": "wo_002", "to": "wo_003"}
],
"hasCycles": false
}
}
5.3 Get Critical Path
GET /v1/work-orders/:id/critical-path
Returns the longest dependency chain through the Master WO's linked WOs with estimated completion dates.
5.4 Get Master WO Progress
GET /v1/work-orders/:id/progress
Returns aggregated progress: total linked WOs, completion percentages, blocked items, estimated completion.
6. Audit Trail Endpoints
6.1 Get Audit Trail
GET /v1/work-orders/:id/audit-trail?limit=50&cursor=xxx
Authorization: audit:read (QA, SYSTEM_OWNER, AUDITOR, ADMIN)
Response:
{
"data": [
{
"id": "aud_001",
"entityType": "WorkOrder",
"entityId": "wo_clu789",
"action": "STATUS_CHANGE",
"performedBy": "user_abc",
"performedByName": "John Doe",
"performedByRole": "ASSIGNER",
"performedAt": "2026-02-13T15:00:00Z",
"previousValue": "{\"status\":\"DRAFT\"}",
"newValue": "{\"status\":\"PENDING_APPROVAL\"}",
"reason": "Job plan complete",
"ipAddress": "10.0.1.42",
"userAgent": "CODITECT-Web/1.0",
"chainHash": "sha256:abc123..."
}
],
"pagination": { "cursor": "...", "has_more": true, "total_count": 47 },
"chainIntegrity": {
"verified": true,
"entriesChecked": 47,
"lastVerifiedAt": "2026-02-13T15:05:00Z"
}
}
Compliance: Audit trail entries are immutable. No UPDATE or DELETE operations exist. chainHash enables tamper detection per 64-security-architecture.md §1 (STRIDE: Tampering).
6.2 Export Audit Trail
GET /v1/work-orders/:id/audit-trail/export?format=pdf|csv|json
Authorization: audit:export (AUDITOR, ADMIN) — rate limited per tier.
Generates a compliance evidence package suitable for FDA inspection (see 75-audit-readiness-guide.md).
7. Resource Endpoints
7.1 Resource Matching
POST /v1/resources/match
Request:
{
"workOrderId": "wo_clu789",
"requirements": {
"tools": ["tool_wrench_set"],
"experience": ["exp_hplc_maintenance"],
"personCount": 2,
"scheduledStart": "2026-03-15T09:00:00Z",
"scheduledEnd": "2026-03-15T17:00:00Z"
}
}
Response: Ranked candidate list with availability, experience match score, and cost.
7.2 Asset Registry
GET /v1/assets?search=HPLC&status=ACTIVE&limit=25
GET /v1/assets/:id
POST /v1/assets (ADMIN only)
PUT /v1/assets/:id (ADMIN only)
7.3 Person Registry
GET /v1/persons?team=calibration&experience=hplc_maintenance
GET /v1/persons/:id
GET /v1/persons/:id/experience (experience + certifications with expiry)
GET /v1/persons/:id/availability (schedule for date range)
7.4 Tool & Material Registries
GET /v1/tools?calibrationDueBefore=2026-04-01
GET /v1/materials?belowMinimum=true
8. Risk Assessment Endpoints
Per G16 (CAPA workflow — see 74-capa-workflow.md):
8.1 Create Risk Assessment
POST /v1/work-orders/:id/risk-assessment
Request:
{
"likelihood": 3,
"impact": 4,
"category": "COMPLIANCE" | "SAFETY" | "OPERATIONAL" | "DATA_INTEGRITY",
"mitigationPlan": "...",
"residualRisk": 6
}
Guard integration: WO cannot transition to PENDING_REVIEW if regulatory: true and no risk assessment exists.
8.2 Get Risk Assessment
GET /v1/work-orders/:id/risk-assessment
9. Health & System Endpoints
GET /v1/health # Basic health (public, no auth)
GET /v1/health/detailed # Component health (ADMIN only)
GET /v1/health/compliance # Compliance engine status (QA, ADMIN)
GET /v1/metrics # Prometheus metrics (internal network only)
10. Webhook Delivery
Outbound webhooks per 67-integration-api-strategy.md §4:
POST {customer_webhook_url}
Headers:
X-Webhook-ID: evt_uuid7
X-Webhook-Signature: sha256=hmac_signature
X-Webhook-Timestamp: 1707836400
Content-Type: application/json
Subscribable Events:
| Event | Trigger | Payload Key Fields |
|---|---|---|
work_order.created | WO created | id, type, regulatory, priority |
work_order.status_changed | Status transition | id, previousStatus, newStatus, reason |
work_order.approval_requested | Approval created | id, approverId, role, dueDate |
work_order.approval_decided | Approval submitted | id, approvalId, decision |
work_order.completed | WO reaches COMPLETED | id, completedAt, duration |
work_order.closed | WO reaches CLOSED | id, closedAt, full summary |
work_order.blocked | WO enters BLOCKED | id, blockReason |
compliance.violation_detected | Compliance engine finding | workOrderId, violation, severity |
11. Cross-Reference
| Concern | Specification Source |
|---|---|
| State machine transitions | 19-state-machine-with-guards.md |
| RBAC per endpoint | 22-rbac-permissions-matrix.md |
| Data model schemas | 16-prisma-data-model.md |
| E-signature flow | 17-e-signature-architecture.md |
| Agent message contracts | 26-agent-message-contracts.md |
| API design philosophy | 67-integration-api-strategy.md §2 |
| Error experience | 68-user-experience-journeys.md §5 |
| Rate limit tiers | 60-business-model.md (subscription tiers) |
| Webhook architecture | 67-integration-api-strategy.md §4 |
This specification is the contract between frontend, agent, and integration consumers. All endpoint behavior is validated by integration tests (65-testing-strategy.md §1) and contract tests. Breaking changes require API versioning per 69-versioning-evolution-strategy.md §1.