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.
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.
Each read costs 1 credit. The first time your organization reads a given case's analysis, that read is priced instead at the credits generating the analysis actually used, up to 400 credits. Every later read of that case by anyone in your organization is 1 credit again.
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));