Search | API Reference Guide | CourtMesh
    Skip to main content

    Search

    Keyword search across the full corpus, meaning based semantic search over the analysed subset, and judge name lookup.

    Search endpoints
    Three ways to find a case: keyword, semantic, and by judge.
    POST

    /search/cases

    1 credit

    Keyword search across 315.6 million case records from the Supreme Court, all 25 High Courts, District Courts and Tribunals. This is the endpoint that sees the whole corpus.

    Request body

    FieldTypeRequiredNotes
    querystringYesSearch text. Trimmed, must be at least 1 character. Case numbers work here: put 123-2024 in the query rather than in caseNumber.
    courtstring | string[]NoCourt name or names. Comma separated strings are also split, so "Bombay High Court,Delhi High Court" behaves like an array.
    yearnumber | string | arrayNoFour digit year, or an array of them. Must be between 1947 and the current year.
    caseTypestring | string[]NoCase type label or code. Labels are expanded server side to the full set of codes they cover, so "Appeal" matches CA, CRA, LPA and the rest.
    judgeNamestring | string[]NoJudge name. judges and judge are accepted as aliases; the first one present wins. Use GET /judges/search to get exact spellings.
    fromDatestringNoInclusive lower bound on decision date, YYYY-MM-DD. Any other format is rejected with HTTP 400.
    toDatestringNoInclusive upper bound on decision date, YYYY-MM-DD.
    pagenumberNoPage number, default 1, minimum 1. Must be a JSON number. A quoted string is rejected with HTTP 400.
    limitnumberNoResults per page, default 20, maximum 100. Must be a JSON number.
    searchAfterstringNoCursor from the previous response. Prefer this over page for anything beyond the first few pages.
    sortByenumNoOne of relevance (default), recent, oldest. See the note below on the deprecated value date.
    caseNumberstring | string[]NoACCEPTED BUT INERT. The schema allows it and the response echoes it back in meta.filters, but the handler never forwards it to the search engine, so it does not narrow results. Put the case number in query instead.
    practiceAreanot supportedNoNOT A PARAMETER. It is absent from the schema, and unknown keys are stripped silently during validation, so sending it produces no error and no filtering.

    Sorting

    sortBy takes relevance (the default), recent for newest decision date first, or oldest for the reverse. The value date is a deprecated alias kept only so that existing integrations do not start failing validation. The search layer does not understand it and silently ranks by relevance instead, so it is not a way to sort by date. Use recent or oldest.

    Unknown keys are dropped, not rejected

    The body is parsed against a fixed schema and anything outside it is removed before the handler runs. That is why sending practiceArea produces neither an error nor a filtered result set. If a filter you sent does not appear in the meta.filters echo of the response, it was not applied. The one filter that appears in that echo and is still not applied is caseNumber.

    Every response also carries meta.someRecordsWithheld, a boolean noting whether a restricted or de-indexed record was left out of the results, and on a degraded restricted-record check meta.restrictedCheckDegraded is set to true with affected titles masked in the response.

    curl -X POST https://research.courtmesh.ai/api/v1/prod/search/cases \
      -H "X-API-Key: cm-YOUR_KEY_HERE" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "property dispute adverse possession",
        "court": ["Bombay High Court", "Delhi High Court"],
        "year": [2006, 2007],
        "judgeName": "D.Y. CHANDRACHUD",
        "fromDate": "2006-01-01",
        "toDate": "2007-12-31",
        "page": 1,
        "limit": 20,
        "sortBy": "recent"
      }'

    Common validation error

    // HTTP 400. page and limit are JSON numbers, not strings.
    // Sending "limit": "20" fails; sending "limit": 20 passes.
    {
      "success": false,
      "error": "Validation failed. Please check your request and try again.",
      "details": ["limit: Expected number, received string"]
    }