Cases | API Reference Guide | CourtMesh
    Skip to main content

    Cases

    Fetch one case by id: its detail, its stored AI analysis, documents related to it, and its judgment PDF.

    Case endpoints
    Everything keyed off a single case id.
    GET

    /cases/:id

    1 credit

    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"
    GET

    /cases/:id/analysis

    1 creditAI

    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"

    Analysis fields

    • summary and detailedSummary, short and long form
    • headnote, the extracted legal headnote
    • keyFacts, facts the model identified
    • issues, each with a question and the holding on it
    • courtsReasoning, the reasoning chain
    • citedCases, split into followed, distinguished, overruled and referred
    • practiceAreas, legalPrinciples and precedentValue

    These are model outputs. Treat them as a research aid and verify anything load bearing against the judgment PDF.

    GET

    /cases/:id/pdf

    5 credits

    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"

    Decrypting the URL

    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));