Cases API Documentation

Case management and tracking system

Cases API

Comprehensive case management from creation to resolution

Overview

The Cases API provides comprehensive case management capabilities including case creation from inquiries, follow-up tracking, status management, contractor assignment, and complete lifecycle management from opening to resolution.

Case Statuses

  • open
  • in_progress
  • pending_customer
  • pending_contractor
  • resolved
  • closed
  • cancelled

Full metadata (label, description, color, is_terminal) available via GET /api/cases/meta/statuses.

Priority Levels

  • low
  • normal
  • high
  • urgent

Features

  • Inquiry linking
  • Follow-up tracking
  • Tag management
  • Contractor assignment
  • Rich metadata
  • Status audit history
  • Transition validation

Note: Cases can be created standalone, from inquiries, or from orders (and are designed to extend to other sources). They support parent-child relationships for follow-up tracking and can be linked to orders, offers, and invoices.

Status engine: case status changes are validated against the shared transitions catalog. Available transitions can be inspected via GET /api/status-definitions/transitions?entity_type=case. Status history is written to the shared status package when available, with automatic fallback to the legacy case history table.

Method Endpoint Description Requirements
Case Management
POST /api/cases Create a new case
  • customer_id (required) – Customer identifier
  • title (required) – Case title (max 500 chars)
  • description (optional) – Detailed case description
  • contractor_id (optional) – Assigned contractor ID
  • status (optional) – Initial status (default: open)
  • priority (optional) – Priority level (default: normal)
  • parent_case_id (optional) – Parent case for follow-ups
  • initial_inquiry_id (optional) – Link to initial inquiry
  • tags (optional) – Array of tags
  • metadata (optional) – Custom metadata object
  • internal_notes (optional) – Internal notes
  • inquiry_ids (optional) – Array of inquiry IDs to link
  • order_ids (optional) – Array of order IDs to link
  • offer_ids (optional) – Array of offer IDs to link
  • invoice_ids (optional) – Array of invoice IDs to link
GET /api/cases/{id} Retrieve case details by ID
  • id (required) – Case database ID
PUT /api/cases/{id} Update an existing case
  • id (required) – Case database ID
  • title (optional) – Updated title
  • description (optional) – Updated description
  • customer_id (optional) – Updated customer ID
  • contractor_id (optional) – Updated contractor ID
  • status (optional) – Updated status
  • priority (optional) – Updated priority
  • tags (optional) – Updated tags array
  • metadata (optional) – Updated metadata
  • internal_notes (optional) – Updated notes
DELETE /api/cases/{id} Soft delete a case
  • id (required) – Case database ID
POST /api/cases/{id}/restore Restore a soft-deleted case
  • id (required) – Case database ID
Case Creation from Sources
POST /api/cases/from-inquiry/{inquiryId} Create a case from an existing inquiry
  • inquiryId (required) – Inquiry ID to create case from
  • title (optional) – Custom title (defaults from inquiry)
  • description (optional) – Custom description
  • priority (optional) – Priority level
  • contractor_id (optional) – Assign to contractor
POST /api/cases/{parentCaseId}/follow-up Create a follow-up case for an existing case
  • parentCaseId (required) – Parent case ID
  • title (required) – Follow-up case title
  • description (optional) – Follow-up description
  • customer_id (optional) – Overrides parent customer
  • contractor_id (optional) – Assign to contractor
  • status (optional) – Initial status
  • priority (optional) – Priority level
  • tags (optional) – Tags array
  • metadata (optional) – Custom metadata
  • internal_notes (optional) – Internal notes
POST /api/cases/from-order/{orderId} Create a case from an existing order
  • orderId (required) – Order ID to create case from
  • title (optional) – Custom title (defaults from order)
  • description (optional) – Custom description
  • priority (optional) – Priority level
  • contractor_id (optional) – Assign to contractor
  • customer_id (optional) – Override customer when missing on order
Case Actions
POST /api/cases/{id}/action Unified endpoint for all case actions (status updates, assignments, tags, etc.)
  • id (required) – Case database ID
  • action (required) – Action name: update_status, update_priority, assign_contractor, add_tags, remove_tags, attach_inquiries, attach_orders, restore, resolve, close, cancel, reopen, create_follow_up
  • + Additional parameters based on action
Specialized Endpoints
GET /api/cases/timeline Get unified timeline of inquiries and orders by user
  • user_id (optional) – Filter by user ID
  • date_from (optional) – Start date
  • date_to (optional) – End date
  • per_page (optional) – Results per page (default: 15)
GET /api/cases/stats Get case statistics and metrics
  • customer_id (optional) – Filter by customer
  • contractor_id (optional) – Filter by contractor
  • date_from (optional) – Start date
  • date_to (optional) – End date
Reference Data
GET /api/cases/meta/statuses Get all case status definitions with rich metadata: key, label, description, color, and is_terminal flag
GET /api/cases/meta/priorities Get list of available priority levels
Status History
GET /api/cases/{id}/history Get the full status change audit trail for a case, ordered oldest first
  • id (required) – Case database ID
GET /api/status-definitions/transitions?entity_type=case Get the shared transition rules that define allowed case status changes
Case Queries
GET /api/cases/list List cases with filtering and pagination
  • customer_id (optional) – Filter by customer ID
  • contractor_id (optional) – Filter by contractor ID
  • status (optional) – Filter by case status
  • priority (optional) – Filter by priority
  • active_only (optional) – Show only active cases
  • root_only (optional) – Show only root cases (no follow-ups)
  • follow_ups_only (optional) – Show only follow-up cases
  • search (optional) – Search by case number, title, description, customer/contractor ID
  • tags (optional) – Filter by tags (string or array)
  • date_from (optional) – Start date filter (YYYY-MM-DD)
  • date_to (optional) – End date filter (YYYY-MM-DD)
  • order_by (optional) – Sort field (default: created_at)
  • order_direction (optional) – Sort direction (asc/desc, default: desc)
  • per_page (optional) – Results per page (default: 15)
GET /api/cases/customer/{customerId} Get all cases for a specific customer
  • customerId (required) – Customer ID
  • status (optional) – Filter by status
  • priority (optional) – Filter by priority
  • active_only (optional) – Show only active cases
  • date_from (optional) – Start date filter
  • date_to (optional) – End date filter
  • per_page (optional) – Results per page (default: 15)
GET /api/cases/contractor/{contractorId} Get all cases for a specific contractor
  • contractorId (required) – Contractor ID
  • status (optional) – Filter by status
  • priority (optional) – Filter by priority
  • active_only (optional) – Show only active cases
  • date_from (optional) – Start date filter
  • date_to (optional) – End date filter
  • per_page (optional) – Results per page (default: 15)
Statistics & Utilities
GET /api/cases/timeline Get unified timeline of inquiries and orders sorted by date
  • user_id (optional) – Filter by Userhub user ID
  • date_from (optional) – Start date filter (Y-m-d format)
  • date_to (optional) – End date filter (Y-m-d format)
  • per_page (optional) – Results per page (default: 20)
  • page (optional) – Page number (default: 1)
GET /api/cases/stats/overview Get case statistics and analytics
  • customer_id (optional) – Filter statistics by customer
  • contractor_id (optional) – Filter statistics by contractor
  • date_from (optional) – Start date filter
  • date_to (optional) – End date filter
GET /api/cases/statuses/available Get list of all available case statuses
GET /api/cases/priorities/available Get list of all available priorities

Request Examples

Create New Case

POST /api/cases

{ "customer_id": "CUST-12345", "title": "Kitchen renovation project delayed", "description": "Customer reports delays in kitchen renovation. Materials not delivered on time.", "contractor_id": "CONTR-789", "priority": "high", "status": "open", "tags": ["renovation", "delay", "materials"], "metadata": { "project_type": "kitchen", "estimated_value": 15000 }, "inquiry_ids": [42, 43], "order_ids": [123] }

Create Case Response

{ "success": true, "message": "Case created successfully", "data": { "id": 15, "case_number": "20251113-0042", "customer_id": "CUST-12345", "contractor_id": "CONTR-789", "title": "Kitchen renovation project delayed", "description": "Customer reports delays...", "status": "open", "priority": "high", "tags": ["renovation", "delay", "materials"], "metadata": {...}, "created_at": "2025-11-13T10:30:00.000000Z", "updated_at": "2025-11-13T10:30:00.000000Z" } }

Create Case from Inquiry

POST /api/cases/from-inquiry/42

{ "title": "Follow up on kitchen renovation inquiry", "priority": "high", "contractor_id": "CONTR-789" }

Create Case from Order

POST /api/cases/from-order/987

{ "title": "Order 987 delivery follow-up", "description": "Customer reported missing items on delivery.", "priority": "normal", "contractor_id": "CONTR-321" }

Create Follow-up Case

POST /api/cases/15/follow-up

{ "title": "Additional materials needed for kitchen", "description": "Customer requested additional cabinet modifications", "priority": "normal", "tags": ["follow-up", "change-request"] }

Update Case Status (Unified Action Endpoint)

POST /api/cases/15/action

{ "action": "update_status", "status": "in_progress", "notes": "Materials ordered, work scheduled to begin next week" }

Resolve Case

POST /api/cases/15/action

{ "action": "resolve", "resolution_notes": "Issue resolved, customer satisfied" }

Add Tags to Case

POST /api/cases/15/action

{ "action": "add_tags", "tags": ["urgent", "vip-customer"] }

Get Case Status Definitions

GET /api/cases/meta/statuses

Returns rich metadata for all 7 case statuses, including display label, description, color, and whether the status is terminal (i.e. no further transitions expected).

{ "success": true, "data": [ { "key": "open", "label": "Open", "description": "Case has been created and is awaiting action.", "color": "#6B7280", "is_terminal": false }, { "key": "in_progress", "label": "In Progress", "description": "Work is actively being done on this case.", "color": "#3B82F6", "is_terminal": false }, { "key": "pending_customer", "label": "Pending Customer", "description": "Waiting for a response or decision from the customer.", "color": "#F59E0B", "is_terminal": false }, { "key": "pending_contractor", "label": "Pending Contractor", "description": "Waiting for a response or action from the contractor.", "color": "#8B5CF6", "is_terminal": false }, { "key": "resolved", "label": "Resolved", "description": "The main work is finished; closing formalities may remain.", "color": "#10B981", "is_terminal": false }, { "key": "closed", "label": "Closed", "description": "Case is fully completed and archived.", "color": "#059669", "is_terminal": true }, { "key": "cancelled", "label": "Cancelled", "description": "Case was cancelled before completion.", "color": "#EF4444", "is_terminal": true } ] }

Get Case Transition Rules

GET /api/status-definitions/transitions?entity_type=case

Use this endpoint to drive frontend transition pickers and to explain why a transition is or is not allowed.

{ "success": true, "count": 18, "grouped": true, "data": { "case": { "open": [ { "from_status": "open", "to_status": "in_progress" }, { "from_status": "open", "to_status": "pending_customer" }, { "from_status": "open", "to_status": "pending_contractor" }, { "from_status": "open", "to_status": "cancelled" } ], "resolved": [ { "from_status": "resolved", "to_status": "closed" }, { "from_status": "resolved", "to_status": "open" } ], "closed": [ { "from_status": "closed", "to_status": "open" } ] } } }

Get Case Status History

GET /api/cases/15/history

Returns the complete append-only audit trail of all status transitions for a case, ordered oldest first. from_status is null for the initial creation entry.

{ "success": true, "data": [ { "from_status": null, "to_status": "open", "changed_by": null, "note": "Case created", "created_at": "2026-04-16T10:30:00+00:00" }, { "from_status": "open", "to_status": "in_progress", "changed_by": null, "note": "Materials ordered, work scheduled to begin next week", "created_at": "2026-04-17T09:15:00+00:00" }, { "from_status": "in_progress", "to_status": "resolved", "changed_by": null, "note": "Issue resolved, customer satisfied", "created_at": "2026-04-20T16:45:00+00:00" } ] }

Get Case Details Response

GET /api/cases/15

{ "success": true, "data": { "case": { "id": 15, "case_number": "20251113-0042", "customer_id": "CUST-12345", "title": "Kitchen renovation project delayed", "status": "in_progress", "priority": "high", "resolved_at": null, "closed_at": null, "child_cases": [ { "id": 16, "case_number": "20251113-0043", "title": "Additional materials needed" } ] }, "has_follow_ups": true, "is_follow_up": false, "is_active": true, "is_resolved": false, "age_in_days": 3 } }

List Cases Response

GET /api/cases/list?status=in_progress&priority=high

{ "success": true, "data": [ { "id": 15, "case_number": "20251113-0042", "customer_id": "CUST-12345", "title": "Kitchen renovation project delayed", "status": "in_progress", "priority": "high", "created_at": "2025-11-13T10:30:00.000000Z" } ], "pagination": { "current_page": 1, "per_page": 15, "total": 12, "last_page": 1 } }

Unified Timeline Response

GET /api/cases/timeline?user_id=123&per_page=5

{ "success": true, "data": [ { "id": 42, "type": "inquiry", "type_label": "Inquiry", "inquiry_type": { "name": "Question", "icon": "❓", "color": "#3B82F6" }, "user_id": 123, "customer_name": "Jan de Vries", "customer_email": "jan@example.com", "subject": "Verbouwing keuken", "message": "Ik wil graag mijn keuken laten verbouwen...", "status": "in_progress", "priority": "normal", "date": "2025-11-13T14:30:00.000000Z", "date_formatted": "2025-11-13 14:30:00", "timestamp": 1699887000 }, { "id": 89, "type": "order", "type_label": "Order", "order_id": 2025089, "user_id": 123, "customer_id": "jan@example.com", "total": "1500.00", "currency": "€", "status": "completed", "items_count": 3, "date": "2025-11-12T09:15:00.000000Z", "date_formatted": "2025-11-12 09:15:00", "timestamp": 1699781700 }, { "id": 38, "type": "inquiry", "type_label": "Inquiry", "inquiry_type": { "name": "Call-back Request", "icon": "📞", "color": "#10B981" }, "user_id": 123, "customer_name": "Jan de Vries", "customer_email": "jan@example.com", "subject": "Graag telefonisch contact", "message": "Ik ben bereikbaar op werkdagen...", "status": "closed", "priority": "high", "date": "2025-11-10T16:45:00.000000Z", "date_formatted": "2025-11-10 16:45:00", "timestamp": 1699636500 } ], "pagination": { "current_page": 1, "per_page": 5, "total": 23, "last_page": 5, "from": 1, "to": 5 }, "filters": { "user_id": 123, "date_from": null, "date_to": null } }

Case Statistics Response

GET /api/cases/stats/overview

{ "success": true, "data": { "total_cases": 47, "active_cases": 23, "open_cases": 8, "in_progress_cases": 12, "pending_customer_cases": 2, "pending_contractor_cases": 1, "resolved_cases": 15, "closed_cases": 8, "cancelled_cases": 1, "high_priority_cases": 5, "urgent_priority_cases": 2, "follow_up_cases": 14 } }