Endpoints — Precedents

← Back to Platform Architecture

Endpoints — Precedents

Core CRUD, versioning, and export endpoints for managing precedent objects.

POST /api/precedents

Create a new precedent object. Authentication: Required (X-User-Id header) Authorization: admin, biller roles only PHI Validation: All request body scanned for 18 identifiers; rejected with 422 if found

Request Body

{
  "precedent_name": "Cigna IOP Frequency Limit Victory 2024",
  "payer": "Cigna",
  "denial_type": "Frequency Limit",
  "loc": "IOP",
  "status": "Complete",
  
  "policy_reference": {
    "document_url": "https://cigna-intranet/policy-2024.pdf",
    "policy_section": "Section 2.3.1",
    "exact_language": "Frequency limit: 60 days per benefit year for IOP. Review required after 60 days."
  },
  
  "narrative": "Patient with GAF score 35 demonstrates ongoing need for IOP-level care. Clinical deterioration imminent without continued treatment.",
  
  "denial_trigger": "Patient exceeded 60-day frequency limit (day 64 of benefit year)",
  
  "evidence_kit": {
    "required": ["Clinical progress notes (past 30 days)", "Psychiatric evaluation"],
    "recommended": ["Collateral contact documentation"],
    "optional": ["Prior treatment records"]
  },
  
  "outcome": "Won",
  "time_to_resolution_days": 14,
  
  "traceability_ledger": [
    { "event_type": "denial_received", "date": "2024-04-01", "notes": "Denial received via EDI" },
    { "event_type": "appeal_filed", "date": "2024-04-03", "notes": "Appeal submitted with clinical justification" },
    { "event_type": "approved", "date": "2024-04-15", "notes": "Appeal approved, 14 days to resolution" }
  ]
}

Response (201 Created)

{
  "id": "prec-uuid",
  "cluster_id": "Cigna  IOP",
  "tenant_id": "tenant-uuid",
  "precedent_name": "Cigna IOP Frequency Limit Victory 2024",
  "payer": "Cigna",
  "denial_type": "Frequency Limit",
  "loc": "IOP",
  "status": "Complete",
  "outcome": "Won",
  "time_to_resolution_days": 14,
  "evidence_score": "Strong",
  "created_by": "user-uuid",
  "created_at": "2024-04-14T10:30:00Z",
  "updated_at": "2024-04-14T10:30:00Z",
  "archived": false
}

Errors

400 Bad Request — Invalid request schema (missing required field, wrong type)
{
  "error": "VALIDATION_ERROR",
  "details": [
    { "path": "payer", "message": "Required" }
  ]
}
422 Unprocessable Entity — PHI detected in request
{
  "status": "error",
  "type": "phi_detected",
  "message": "Protected Health Information detected: phone",
  "offending_identifier": "phone"
}
403 Forbidden — User role insufficient
{
  "error": "INSUFFICIENT_ROLE",
  "message": "Create precedent requires admin or biller role"
}

GET /api/precedents

List precedent objects with pagination, filtering, and sorting. Authentication: Required Authorization: Any authenticated user

Query Parameters

Example

GET /api/precedents?payer=Cigna&outcome=Won&limit=20&offset=0&sort_by=time_to_resolution_days&sort_direction=asc

Response (200 OK)

{
  "data": [
    {
      "id": "prec-1",
      "cluster_id": "Cigna 
IOP", "precedent_name": "Cigna IOP Frequency Limit Victory 2024", "payer": "Cigna", "denial_type": "Frequency Limit", "loc": "IOP", "outcome": "Won", "time_to_resolution_days": 14, "evidence_score": "Strong", "created_at": "2024-04-14T10:30:00Z" } ], "total": 247, "limit": 20, "offset": 0, "has_more": true }

GET /api/precedents/:id

Retrieve a single precedent object. Authentication: Required Authorization: Any authenticated user (tenant-filtered)

Response (200 OK)

{
  "id": "prec-uuid",
  "cluster_id": "Cigna 
Frequency Limit
ParameterTypeDefaultExample
limitinteger2050
offsetinteger0100
sort_bystringcreated_atoutcome, payer, time_to_resolution_days
sort_directionstringdescasc
payerstring(none)Cigna
denial_typestring(none)Frequency Limit
locstring(none)IOP
outcomestring(none)Won, Lost, Partial, Pending
cluster_idstring(none)Cigna \Frequency Limit \IOP
statusstring(none)Complete, Draft, Pending
min_evidence_scorestring(none)Minimal, Moderate, Strong
created_afterdate(none)2024-04-01
created_beforedate(none)2024-12-31
include_archivedbooleanfalsetrue
Frequency Limit
Frequency Limit
IOP", "tenant_id": "tenant-uuid", "precedent_name": "Cigna IOP Frequency Limit Victory 2024", "payer": "Cigna", "denial_type": "Frequency Limit", "loc": "IOP", "status": "Complete", "policy_reference": { ... }, "narrative": "...", "denial_trigger": "...", "evidence_kit": { ... }, "outcome": "Won", "time_to_resolution_days": 14, "evidence_score": "Strong", "traceability_ledger": [ ... ], "created_by": "user-uuid", "created_at": "2024-04-14T10:30:00Z", "updated_at": "2024-04-14T10:30:00Z", "archived": false }

Errors

404 Not Found — Precedent doesn't exist or is archived
{ "error": "NOT_FOUND" }

PUT /api/precedents/:id

Update a precedent object. Creates immutable version snapshot; never overwrites original. Authentication: Required Authorization: admin, biller roles only PHI Validation: Request body scanned for PHI; rejected with 422 if found

Request Body

Any fields can be updated:
{
  "narrative": "Updated clinical narrative with additional evidence...",
  "evidence_score": "Strong",
  "outcome": "Partial",
  "traceability_ledger": [ ... ]
}

Response (200 OK)

Returns updated precedent (same structure as GET /api/precedents/:id).

Behavior

  • Version Snapshot — Current state is snapshot to precedent_version_history table before update
  • Updateprecedent_objects row updated in place
  • Audit Logging — Event logged to precedent_audit_log with user_id, changed_fields
  • Cluster Recalculation — Pipeline re-runs cluster aggregation for this cluster_id

  • POST /api/precedents/:id/outcome

    Record appeal outcome for a precedent (shorthand for PUT with outcome field). Authentication: Required Authorization: admin, biller roles only

    Request Body

    {
      "outcome": "Won",
      "time_to_resolution_days": 14,
      "notes": "Appeal approved by medical reviewer"
    }

    Response (200 OK)

    {
      "id": "prec-uuid",
      "outcome": "Won",
      "time_to_resolution_days": 14,
      "updated_at": "2024-04-14T10:30:00Z"
    }

    GET /api/precedents/:id/versions

    Retrieve version history for a precedent. Authentication: Required Authorization: Any authenticated user

    Response (200 OK)

    {
      "data": [
        {
          "version_number": 1,
          "snapshot": { ... full precedent state ... },
          "saved_by": "user-uuid",
          "saved_at": "2024-04-14T10:00:00Z",
          "version_reason": "Initial creation"
        },
        {
          "version_number": 2,
          "snapshot": { ... full precedent state after update ... },
          "saved_by": "user-uuid",
          "saved_at": "2024-04-14T10:30:00Z",
          "version_reason": "Updated outcome to Won"
        }
      ]
    }

    POST /api/precedents/:id/apply

    Record that this precedent was used for an appeal case (increments reuse counter). Authentication: Required Authorization: admin, biller roles only

    Request Body

    {
      "appeal_id": "appeal-uuid",
      "notes": "Used as precedent for Cigna frequency limit appeal"
    }

    Response (200 OK)

    { "success": true }

    DELETE /api/precedents/:id

    Archive a precedent (soft delete). Authentication: Required Authorization: admin role only

    Response (200 OK)

    {
      "success": true,
      "id": "prec-uuid",
      "archived": true,
      "archived_at": "2024-04-14T10:30:00Z"
    }

    GET /api/precedents/:id/export

    Export single precedent as JSON or CSV, with optional de-identification. Authentication: Required Authorization: admin, biller roles (biller cannot de-identify) Query Parameters: