All requests require an API key passed in the X-API-Key header:
X-API-Key: your_api_key_here
{baseUrl}/api/partner/v1
POST /cases
Content-Type: application/json
X-API-Key: your_api_key
{
"external_case_id": "YOUR-REFERENCE-001",
"ombudsman": "your_tenant_id",
"case_type_id": "your_case_type_uuid",
"case_title": "Customer billing dispute"
}
| Field | Required | Type | Description |
|---|---|---|---|
external_case_id |
Yes | string | Your unique case reference |
ombudsman |
Yes | string | Your tenant ID (provided during onboarding) |
case_type_id |
Recommended | uuid | Case type for field extraction |
case_title |
No | string | Human-readable case title |
case_initiated_date |
No | string | ISO 8601 date (e.g., "2025-01-15") |
{
"case_id": "80058c5f-100e-428d-b547-79da822b736b",
"external_case_id": "YOUR-REFERENCE-001",
"ombudsman": "your_tenant_id",
"case_type_id": "2b5b8bcd-3a0d-4a22-a5b9-53d4a58c1496",
"case_type_name": "Default",
"status": "created",
"case_title": "Customer billing dispute",
"case_summary": null,
"case_specific_fields": null,
"processing_started_at": null,
"processing_completed_at": null,
"created_at": "2026-02-02T10:21:41.558Z",
"updated_at": "2026-02-02T10:21:41.558Z",
"chronology": [],
"evidence": []
}
case_id - you'll need it for all subsequent requests.
Upload PDF, DOCX, or image files as evidence. Each document is automatically queued for AI processing.
POST /cases/{case_id}/evidence
Content-Type: multipart/form-data
X-API-Key: your_api_key
file: [binary file data]
{
"document_id": "1d7e21ab-fb5d-40ca-b6bf-b14357ce11d9",
"case_id": "80058c5f-100e-428d-b547-79da822b736b",
"external_document_id": null,
"status": "pending_processing",
"uploaded_at": "2026-02-02T10:22:11.544Z",
"title": null,
"short_description": null,
"summary": null,
"case_insights": null,
"event_date": null,
"event_date_start": null,
"event_date_end": null,
"claimant_support_score": null,
"defendant_support_score": null
}
Poll each document until all reach processing_complete status before proceeding to Step 3.
| Status | Description |
|---|---|
| pending_processing | Document uploaded, waiting in queue |
| processing | AI is analyzing the document |
| processing_complete | Processing finished, AI fields populated |
| processing_failed | Processing failed |
Poll 1 (5s): doc1: processing_complete, doc2: processing_complete, doc3: pending_processing
Poll 2 (10s): doc1: processing_complete, doc2: processing_complete, doc3: processing
Poll 3 (15s): doc1: processing_complete, doc2: processing_complete, doc3: processing_complete
{
"document_id": "1d7e21ab-fb5d-40ca-b6bf-b14357ce11d9",
"case_id": "80058c5f-100e-428d-b547-79da822b736b",
"external_document_id": null,
"status": "processing_complete",
"uploaded_at": "2026-02-02T10:22:11.544Z",
"title": "Complaint Form - Jack Grainger v Sonicwave - Contract Discount and Early Termination Fee Dispute",
"short_description": "Customer complaint regarding removal of contractual monthly discount and disputed early termination fee charged by Sonicwave.",
"summary": "# Complaint Form - Jack Grainger v Sonicwave...\n\nThis is a formal complaint submission form documenting a dispute between a customer and their service provider...",
"case_insights": "- Claimant's position: discount was for full contract duration\n- Disputes April price increase\n- Disputes £130 ETF\n- Remedy sought: £12 + £130 refund minimum\n- First complained: 15/07/2025\n- Deadlock letter received: 18/05/2025",
"event_date": "2025-07-15T00:00:00.000Z",
"event_date_start": "2025-07-15T00:00:00.000Z",
"event_date_end": "2025-07-15T00:00:00.000Z",
"claimant_support_score": 7,
"defendant_support_score": 2
}
case_insights and support scores are populated after document processing completes. These provide key facts relevant to the dispute and indicate how strongly the document supports each party.
Once all documents have status: processing_complete, trigger the AI case assessment.
{
"case_id": "80058c5f-100e-428d-b547-79da822b736b",
"status": "processing"
}
If any documents are still processing:
{
"statusCode": 400,
"message": "Cannot process case: documents are still being processed"
}
Poll the case endpoint until status changes to processed.
| Status | Description |
|---|---|
| created | Case created, awaiting documents |
| processing | AI assessment in progress |
| processed | Assessment complete |
| error | Assessment failed |
[10s] Status: processing
[20s] Status: processing
[30s] Status: processing
...
[120s] Status: processed
Once status is processed, the case contains the complete AI assessment.
{
"case_id": "80058c5f-100e-428d-b547-79da822b736b",
"external_case_id": "JACK-GRAINGER-1770027701",
"ombudsman": "your_tenant_id",
"case_type_id": "2b5b8bcd-3a0d-4a22-a5b9-53d4a58c1496",
"case_type_name": "Default",
"status": "processed",
"case_title": "Broadband Promotional Pricing And Termination Fee",
"case_summary": "This case concerns a dispute between a broadband customer and their provider over promotional pricing terms and early termination fees. The claimant believed a £12 monthly discount would apply for the full 18-month contract term, but the provider applied it only for the first 12 months as stated in the welcome email...",
"case_specific_fields": "- Claimant: Jack Grainger\n- Respondent: Sonicwave Broadband Ltd\n- ABTA Case Reference: Not found\n- Internal Case Reference: CW-2025-038\n- Total Holiday Cost: Not found\n- Amount Claimed: £142.00\n- Pre-Arbitration Offer: Not found",
"processing_started_at": null,
"processing_completed_at": "2026-02-02T10:26:15.922Z",
"created_at": "2026-02-02T10:21:41.558Z",
"updated_at": "2026-02-02T10:26:15.922Z",
"chronology": [...],
"evidence": [...]
}
| Field | Type | Description |
|---|---|---|
case_id |
uuid | Internal case identifier |
external_case_id |
string | Your case reference |
status |
string | Case status |
case_title |
string | AI-generated case title |
case_summary |
string | AI-generated comprehensive case summary |
case_specific_fields |
string | Extracted case-specific fields as markdown bullet list (based on case type configuration) |
processing_completed_at |
string | ISO timestamp when assessment completed |
chronology |
array | AI-generated timeline of events |
evidence |
array | List of evidence documents with AI analysis |
| Field | Type | Description |
|---|---|---|
document_id |
uuid | Document identifier |
external_document_id |
string | Your document reference (if provided) |
status |
string | Processing status |
title |
string | AI-generated document title |
short_description |
string | Brief summary (1-2 sentences) |
summary |
string | Full markdown summary |
case_insights |
string | Key facts relevant to the dispute |
event_date |
string | Primary date from document |
event_date_start |
string | Date range start |
event_date_end |
string | Date range end |
claimant_support_score |
integer | How strongly document supports claimant (0-10) |
defendant_support_score |
integer | How strongly document supports defendant (0-10) |
| Field | Type | Description |
|---|---|---|
timeline_id |
uuid | Timeline entry identifier |
title |
string | Event title |
description |
string | Event description |
timeline_date |
string | ISO timestamp of event |
documents |
array | Associated document references |
is_ai_generated |
boolean | Whether entry was AI-generated |
The case_specific_fields contains AI-extracted key information as a markdown-formatted bullet list. The fields extracted depend on the case type configuration.
{
"case_specific_fields": "- Claimant: Jack Grainger\n- Respondent: Sonicwave Broadband Ltd\n- ABTA Case Reference: Not found\n- Internal Case Reference: CW-2025-038\n- Total Holiday Cost: Not found\n- Amount Claimed: £142.00\n- Pre-Arbitration Offer: Not found"
}
The AI extracts and orders key events from all documents:
{
"chronology": [
{
"timeline_id": "cd49cd8b-1af5-4ba2-a874-1a9bd2c6f2a9",
"title": "Contract signed",
"description": "Jack Grainger signed an 18-month contract with Sonicwave for the Ultimate Fibre 100 plan.",
"timeline_date": "2024-04-03T00:00:00.000Z",
"documents": [
{"document_id": "3e75c2b8-2dac-4618-80f0-c4f94bc02557", "external_document_id": null}
],
"is_ai_generated": true
},
{
"timeline_id": "52d24b05-f4f8-4bb3-8ea2-d7038e7da224",
"title": "Promotional period ended",
"description": "The 12-month promotional period at £23.99/month ended, after which the standard rate of £35.99/month applied.",
"timeline_date": "2025-04-07T00:00:00.000Z",
"documents": [
{"document_id": "c239cd5e-17c6-4f77-9304-71721e5f1565", "external_document_id": null}
],
"is_ai_generated": true
},
{
"timeline_id": "2b0cffd1-c718-4709-af07-fd39e2984888",
"title": "Cancellation requested",
"description": "Jack Grainger contacted Sonicwave via chat to terminate his broadband contract. Agent confirmed an early termination fee would apply.",
"timeline_date": "2025-05-09T00:00:00.000Z",
"documents": [
{"document_id": "2ca24f0c-e116-4d52-9dae-eb3d63bee4b6", "external_document_id": null}
],
"is_ai_generated": true
},
{
"timeline_id": "56136799-f3e0-4208-b09e-3ae52119cfa7",
"title": "Deadlock letter issued",
"description": "Sonicwave issued a final response confirming the early termination fee was applied in accordance with terms.",
"timeline_date": "2025-05-18T00:00:00.000Z",
"documents": [
{"document_id": "3e75c2b8-2dac-4618-80f0-c4f94bc02557", "external_document_id": null}
],
"is_ai_generated": true
}
]
}
Each document is analyzed for how strongly it supports each party:
{
"evidence": [
{
"document_id": "f56d4437-0900-4e63-9f39-529d82c46d1c",
"title": "Sonicwave Broadband Welcome Email - Ultimate Fibre 100 Plan",
"short_description": "Welcome email confirming subscription with promotional pricing.",
"case_insights": "- Contract term: 18 months\n- Months 1-12: £23.99 (promotional)\n- After 12 months: £35.99 (standard)\n- Early exit fee: £130.00 clearly stated\n- Critical evidence supporting defendant's position",
"claimant_support_score": 2,
"defendant_support_score": 9
},
{
"document_id": "1d7e21ab-fb5d-40ca-b6bf-b14357ce11d9",
"title": "Complaint Form - Contract Discount and Early Termination Fee Dispute",
"short_description": "Customer complaint regarding removal of contractual discount.",
"case_insights": "- Claimant's position: discount was for full contract duration\n- Disputes £130 ETF\n- Remedy sought: £12 + £130 refund minimum",
"claimant_support_score": 7,
"defendant_support_score": 2
},
{
"document_id": "c239cd5e-17c6-4f77-9304-71721e5f1565",
"title": "Chat log - Billing Increase Query",
"short_description": "Customer service chat about price increase from £23.99 to £35.99.",
"case_insights": "- Agent confirmed promotional terms were in welcome email\n- Jack admits he 'must have missed that in the email'\n- No retention offers available",
"claimant_support_score": 4,
"defendant_support_score": 7
}
]
}
| Status Code | Meaning | Action |
|---|---|---|
400 |
Invalid request | Check request format, UUIDs, required fields |
401 |
Unauthorized | Verify API key |
404 |
Not found | Verify case_id or document_id exists |
500 |
Server error | Retry request |
{
"statusCode": 400,
"message": "Validation failed (uuid is expected)"
}
| Stage | Typical Duration |
|---|---|
| Document processing (per document) | 10-30 seconds |
| AI case assessment (after /process) | 60-180 seconds |
| Total end-to-end (9 documents) | 3-5 minutes |
import requests
import time
API_KEY = "your_api_key"
BASE_URL = "{baseUrl}/api/partner/v1"
HEADERS = {"X-API-Key": API_KEY}
# Step 1: Create case
case_response = requests.post(
f"{BASE_URL}/cases",
headers={**HEADERS, "Content-Type": "application/json"},
json={
"external_case_id": "MY-CASE-001",
"ombudsman": "your_tenant_id",
"case_type_id": "your_case_type_uuid",
"case_title": "Customer dispute"
}
)
case_id = case_response.json()["case_id"]
print(f"Created case: {case_id}")
# Step 2: Upload documents
document_ids = []
for file_path in ["complaint.pdf", "contract.pdf", "correspondence.pdf"]:
with open(file_path, "rb") as f:
response = requests.post(
f"{BASE_URL}/cases/{case_id}/evidence",
headers=HEADERS,
files={"file": f}
)
document_ids.append(response.json()["document_id"])
print(f"Uploaded: {file_path}")
# Step 2b: Wait for document processing
print("Waiting for document processing...")
while True:
all_complete = True
for doc_id in document_ids:
response = requests.get(
f"{BASE_URL}/cases/{case_id}/evidence/{doc_id}",
headers=HEADERS
)
if response.json()["status"] != "processing_complete":
all_complete = False
break
if all_complete:
print("All documents processed!")
break
time.sleep(5)
# Step 3: Trigger assessment
requests.post(f"{BASE_URL}/cases/{case_id}/process", headers=HEADERS)
print("Assessment triggered")
# Step 4: Wait for assessment
print("Waiting for AI assessment...")
while True:
response = requests.get(f"{BASE_URL}/cases/{case_id}", headers=HEADERS)
status = response.json()["status"]
print(f"Status: {status}")
if status in ["processed", "error"]:
break
time.sleep(10)
# Step 5: Get results
result = requests.get(f"{BASE_URL}/cases/{case_id}", headers=HEADERS).json()
print(f"Case Title: {result['case_title']}")
print(f"Summary: {result['case_summary']}")
print(f"Timeline Events: {len(result['chronology'])}")
print(f"Documents Analyzed: {len(result['evidence'])}")