Fetch one case by id: its detail, its stored AI analysis, documents related to it, and its judgment PDF.
One case record. The :id segment accepts either the document identifier or a case number. AI analysis is deliberately excluded from this response; fetch it separately from /cases/:id/analysis and use the hasAnalysis flag to decide whether that call is worth making. Text fields are watermarked per account.
curl https://research.courtmesh.ai/api/v1/prod/cases/507f1f77bcf86cd799439011 \
-H "X-API-Key: cm-YOUR_KEY_HERE"The stored AI analysis for a case. This is a read, not a generation: it returns whatever has already been produced. If hasAnalysis comes back false, the analysis has not been generated yet and meta.note tells you to call POST /cases/:id/analyze.
Not available on the Free tier. Free Developer keys are refused HTTP 403 with code: "API_TIER_NOT_ALLOWED" on this read too, not only on the two endpoints that generate an analysis. There is no small monthly allowance: the Free tier gets zero AI analysis endpoints, full stop.
curl https://research.courtmesh.ai/api/v1/prod/cases/507f1f77bcf86cd799439011/analysis \
-H "X-API-Key: cm-YOUR_KEY_HERE"summary and detailedSummary, short and long formheadnote, the extracted legal headnotekeyFacts, facts the model identifiedissues, each with a question and the holding on itcourtsReasoning, the reasoning chaincitedCases, split into followed, distinguished, overruled and referredpracticeAreas, legalPrinciples and precedentValueThese are model outputs. Treat them as a research aid and verify anything load bearing against the judgment PDF.
A time limited link to the judgment PDF. The link is a presigned URL valid for one hour, and it is returned encrypted, so cache the case identifier rather than the URL. A 404 here carries a machine readable code so you can tell the two failure modes apart: CASE_NOT_FOUND when the case id itself does not resolve, and PDF_NOT_STORED when the case exists but carries no stored document, which also carries a hint pointing you at POST /request-timeline with refresh:true for High Court and District Court cases (tribunal documents cannot be fetched this way at all).
curl https://research.courtmesh.ai/api/v1/prod/cases/507f1f77bcf86cd799439011/pdf \
-H "X-API-Key: cm-YOUR_KEY_HERE"AES-256-CBC. The passphrase is caseId concatenated with caseNumber, both taken from the same response. The key is the SHA-256 of that passphrase, and the value is the hex initialisation vector, a colon, then the hex ciphertext.
const crypto = require('crypto');
function decryptUrl(encryptedUrl, passphrase) {
const key = crypto.createHash('sha256').update(passphrase).digest();
const parts = encryptedUrl.split(':');
if (parts.length !== 2) throw new Error('Invalid encrypted URL format');
const iv = Buffer.from(parts[0], 'hex');
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
let decrypted = decipher.update(parts[1], 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
const response = await fetch(
'https://research.courtmesh.ai/api/v1/prod/cases/507f1f77bcf86cd799439011/pdf',
{ headers: { 'X-API-Key': 'cm-YOUR_KEY_HERE' } }
);
const data = await response.json();
// Passphrase is caseId concatenated with caseNumber, both from data.data
const decryptionKey = data.data.caseId + data.data.caseNumber;
console.log('PDF URL:', decryptUrl(data.data.pdfUrl, decryptionKey));