Skip to main content
    All articles

    Search Filters That Matter: Court, Year, Judge, Case Type

    17 July 202616 min readCourtMesh Team
    Cover card headed Filters Cut Noise, Words Cut Recall, with the line: only one is free

    There is a reflex almost every user of a legal search box shares. The results look noisy, so they add another word. The results get shorter, which feels like progress, and the search is declared improved. It usually was not. Adding a term to a keyword query does not filter the results, it changes the retrieval condition, and every judgment that made your point in different words has just been removed from consideration without anybody being told.

    Filters do something structurally different. Restricting to the Delhi High Court, or to 2019, or to a date window, or to a case type, narrows which records are eligible without touching the vocabulary the engine is matching on. You lose noise and you keep everything relevant that was in scope. This is the single most useful thing to understand about search: filters cut noise, extra query terms cut recall, and only one of those two is free.

    What follows is a field by field guide to POST /search/cases on the CourtMesh API, an endpoint that runs against a keyword index of roughly 310 million case records drawn from official government portals. It covers what each field accepts, what the server does with it, where the validation will refuse you, and, at some length, why judge name is the hardest field in Indian legal data and should be treated with more suspicion than any other.

    query Is the One Field You Cannot Omit

    The request body has exactly one required field: query, a string of at least one character. Everything else is optional. This is worth stating plainly because it shapes how the endpoint should be used. You cannot ask this endpoint for every matter before a court in a year with no search terms at all; there must be something to match on. The filters constrain a search, they do not replace it.

    The practical consequence is that your query string and your filters have different jobs, and confusing them is where most poor result sets begin. The query carries the substance of what you are looking for, in the vocabulary the judgments themselves use. The filters carry everything that is a property of the record rather than of its language: which court decided it, in what year, under what case type, before which judge. Anything that is metadata belongs in a filter field. Putting metadata in the query string, typing the court name or the year into the search box, makes the engine hunt for those strings in the text of judgments, which is a completely different and much worse question.

    The asymmetry that should govern every query you write

    A term added to query is a retrieval condition: judgments that do not contain it, or a lexical variant of it, become unreachable. A filter is an eligibility condition applied to record metadata: judgments that survive it are still matched on the same terms as before. Narrow with filters until the result set is workable, and only then consider touching the query. Practitioners who reverse that order spend their afternoons producing precise, confident, incomplete lists.

    The Full Field List, and What Each One Accepts

    Here is the whole surface in one place. Every field below is on the request body of POST /search/cases.

    FieldAcceptsNotes that matter in practice
    queryString, minimum length 1, requiredThe only mandatory field. Carries the substance of the search. Keep court names, years and case type labels out of it and put them in the filter fields instead.
    courtString, comma separated string, or arrayThe coarsest and most valuable filter. A single call can span several courts, so a query across a group of High Courts does not need one request per court, which matters on a budget of 10 requests per minute.
    caseTypeString, comma separated string, or arrayExpanded server side from a primary type into the underlying registry codes. Asking for Appeal reaches a set such as CA, CRA and LPA rather than matching the literal word.
    caseNumberString, comma separated string, or arrayFor pulling known matters. Exact identifiers belong here rather than in the query string, where they are just tokens competing with everything else.
    judgeNameString, comma separated string, or arrayAliases judges and judge are accepted, so an existing client using either name keeps working. Read the section below before you rely on this field for anything exhaustive.
    yearFour digit number or string, or an array of themValidated between 1947 and the current year. A value outside that window is a validation failure, not a silently empty result set.
    fromDate and toDateStrict YYYY-MM-DD stringsStrict means strict. Any other format is rejected by validation. Use these when a year is too coarse, which for a busy High Court in a recent year it usually is.
    pageInteger, default 1Offset paging, appropriate for interactive screens. Not the right mechanism for walking a large result set.
    limitInteger, default 20, maximum 100Leaving it at 20 costs five times as many calls for the same records. 100 is a hard ceiling, not a clamp: a limit above it is rejected with HTTP 400 and a `details` array reading `limit: Limit cannot exceed 100 results per page.` Nothing is returned, so handle the 400 rather than expecting a truncated page.
    searchAfterString cursorThe correct mechanism for bulk walks. Constant cost per page regardless of depth, unlike incrementing page.
    sortByrelevance or date, defaults to relevanceValidated to those two values. The choice interacts with date filtering in a way that is worth thinking about, covered further down.

    Validation failures come back as an error response carrying a details array of human readable messages, one per offending field and prefixed with the field path. That is worth surfacing in your own client rather than collapsing to a generic bad request, because the message usually names the exact problem: a year below 1947, a date that is not in YYYY-MM-DD, a sortBy value that is neither relevance nor date.

    Court, and the Case Type Field That Expands Underneath You

    Court is the filter to reach for first, every time. It is the axis along which the data is actually produced, and it is the axis along which coverage and metadata quality vary most. The Supreme Court, the 25 High Courts, the the district judiciary and tribunals including NCLT, NCLAT, ITAT, CESTAT, SAT, TDSAT and DRT are not one homogeneous corpus. They are many registries with their own conventions, and a search that does not say which of them it wants is asking a much vaguer question than the user intended.

    That court, caseType, caseNumber and the judge fields all accept a string, a comma separated string, or an array is a small detail with a real consequence for throughput. If you want a point across four High Courts, that is one call with four courts, not four calls. On a budget of 10 requests per minute per key, collapsing a fan out into a single request is often the difference between an interactive feature and a background job.

    Case type is a concept, not a string

    The caseType field is the one most likely to surprise a developer reading the response for the first time. Indian registries do not use a shared vocabulary of case types. What an advocate calls an appeal appears in the record as a family of registry codes: civil appeals, criminal appeals, letters patent appeals and others, each abbreviated according to the conventions of the court that registered it. Anyone who has read a cause list knows the texture: CRL.A., W.P.(C), CS(COMM), O.M.P., SLP, Arb.P., and dozens more, with punctuation and spacing that vary between registries and sometimes between years within the same registry.

    So caseType is expanded server side. You pass a primary type and the endpoint resolves it into the underlying registry codes, such as CA, CRA and LPA for an appeal, and matches against all of them. This is the behaviour you want, and it is also a behaviour you should be aware of, because it means the filter is broader than the literal string you sent. If your requirement is genuinely one specific registry code and not its siblings, the honest approach is to check what came back rather than assuming the filter was literal.

    Why server side expansion is the right default

    The alternative is to make every integrator maintain their own mapping from an ordinary legal concept to the registry abbreviations used across the Supreme Court, 25 High Courts and hundreds of District Court establishments, and to keep that mapping current as registries change practice. That is a standing maintenance obligation with no upside for anyone. Expanding centrally means one mapping is maintained once and every caller gets the benefit. It also means a caller who wants literal precision should verify against the caseType values on the returned records.

    year, fromDate and toDate: Choosing the Right Granularity

    There are two time filters and they are not redundant. year takes a four digit value, or an array of them, and is validated between 1947 and the current year. That lower bound is not arbitrary: it is the beginning of the Republic era record, and a value below it is far more likely to be a bug in the caller than a genuine request. fromDate and toDate take strict YYYY-MM-DD strings and give you an arbitrary window.

    Use year when the question is naturally annual, which most research questions are: what did this court do with this point in 2021, or across 2019, 2020 and 2021. Use a date window when the year is either too coarse or the wrong unit. Three situations recur.

    • A slice too large to page comfortably. A busy High Court in a recent year can match far more records than you want to walk. Cutting the year into quarters or months keeps every query shallow and gives a bulk pull a natural checkpoint boundary.
    • A window defined by an event rather than a calendar. Limitation questions under the Limitation Act 1963, the effect of an amendment coming into force, the period after a Supreme Court judgment settled a point: none of these respect January to December. A date window expresses them directly.
    • Recency monitoring. A watch on new decisions is naturally a rolling window: everything since the last successful run. That is a fromDate, and it should come from your own checkpoint rather than from a hardcoded interval.

    One honest caveat about dates that applies to any aggregation of Indian court data. The date on a record is the date the registry published, and completeness of date metadata varies by court and by year. Older records are thinner than recent ones and District Court records are thinner than Supreme Court records. A tight date window over a court and period with sparse date metadata will return fewer records than exist, and that is a property of the upstream record rather than of the filter. When completeness matters more than precision, prefer year over a narrow window, and treat the registry as the authority.

    Judge Name Is the Messiest Field in Indian Legal Data

    judgeName, with its aliases judges and judge, looks like the simplest filter on the list. It is by some distance the least reliable, and the reasons are worth setting out in detail because they are properties of the underlying records rather than defects anyone can patch away.

    Honorifics travel with the name

    Records carry Hon'ble, Justice, Mr. Justice, Ms. Justice, The Chief Justice and combinations of these, with and without punctuation, sometimes concatenated to the surname without a space. The same judge appears half a dozen ways in a single court's record set.

    Initials are unstable

    A judge may appear with full given names in one registry and as two initials in another, with or without full stops, with or without spaces between them. A substring search for a surname survives this; a search for a full name as recorded in one court frequently does not.

    Spelling varies across registries

    Indian surnames transliterate several defensible ways, and different registries settled on different conventions decades ago. There is no canonical spelling to normalise to, because the courts themselves never agreed on one.

    Benches are sometimes one string

    Some sources record a division bench as a single field containing both names joined by a comma, an ampersand, or the word and. A filter matching a single name against that field behaves differently from one matching against a clean array of judges.

    Elevation and retirement

    A judge elevated from a High Court to the Supreme Court appears under both courts across different periods, and a retired judge's name stops appearing entirely after a date. Any analysis over time has to account for the career, not just the name.

    Namesakes are real

    Common surnames recur across courts and decades. A filter on a surname alone can pull together the work of several unrelated judges, and nothing in the result set will tell you that it has done so.

    What GET /judges/search does, and what it does not

    There is a companion endpoint, GET /judges/search with a q parameter, and it is genuinely useful provided you understand its scope. It performs a case insensitive substring match over a combined Supreme Court and High Court judge name list and returns a plain array of name strings, capped at 50, with meta carrying the query, a responseTime and a totalMatches. An empty q returns a default 50. It is cheap, it consumes no AI credit, and it is exactly the right thing behind an autocomplete box.

    The important limitation is that it searches a curated name list, not the case corpus. A name that is not on that list will not be returned even if it appears in judgments, and a name that is on the list is not thereby guaranteed to be spelled the same way in every record you are about to filter. So the endpoint is an aid to entering a plausible, well formed name. It is not a guarantee that filtering on that name will retrieve every matter the judge decided.

    Use judge name to explore, never to be exhaustive. If the answer to your question changes depending on whether a judgment was retrieved, a judge filter is the wrong foundation to build that answer on.

    The practical protocol follows from all of this. Filter on court and period first, so that the eligible set is small and coherent. Add judge as a narrowing hint rather than as the load bearing condition. Where a name has plausible variants, pass them together, since the field accepts a comma separated string or an array, so several spellings can be tried in one request rather than in several. And when the output is going to be relied upon, read the judges array on the returned records and confirm the names yourself.

    How sortBy Interacts With Date Filtering

    sortBy validates to relevance or date and defaults to relevance. The default is right for most searches: a relevance ordering puts the judgments that best match your terms at the top, which is what a researcher wants when the question is what does the authority say.

    Date ordering answers a different question, and the tell for when you need it is when the shape of the answer is chronological rather than topical. Three cases come up constantly.

    1

    Tracing how a point developed

    When you want the line of authority in order, from the earliest treatment through to the most recent, relevance ordering actively works against you by interleaving decades. Sort by date and read the sequence. This is how you notice that the reasoning predates the label that was later attached to it.

    2

    Monitoring what is new

    A watch over a rolling window, meaning a fromDate taken from your last successful run, needs the newest first. Relevance ordering on a recency feed will bury a two day old decision beneath a better matching judgment from 2014, which is exactly the wrong behaviour for an alerting product.

    3

    Walking a slice exhaustively

    For a bulk pull with a cursor, a date ordering gives a stable, meaningful traversal and makes a partially completed slice interpretable: you know precisely how far through the period you got. Relevance ordering gives you a position in a ranking that means nothing once the job is interrupted.

    There is a subtlety worth naming. Applying fromDate and toDate does not change the ordering, only the eligible set. A tight date window with relevance ordering is perfectly coherent and is usually what you want for research: the best matches within a period. It is only when the period itself is the subject of the question, rather than a constraint on it, that the sort should change. Put another way, filter by date to decide what counts, and sort by date to decide what the answer looks like.

    Paging, Briefly, Because It Changes What Filters Are For

    page, limit and searchAfter are covered at length in a companion post, so the summary here is deliberately short. page and limit are offset paging, appropriate when a human is looking at results and will stop within a few screens. searchAfter is a cursor and is the correct mechanism for walking a large set, because its cost per page does not grow with depth. limit defaults to 20 and accepts up to 100, and leaving it at the default multiplies your call count by five for no benefit.

    The reason it belongs in an article about filters is that good filtering is what keeps paging shallow. A well filtered query returns a set you can walk in tens of pages. A badly filtered query returns a set you can only walk in thousands, and every problem that follows, the timeouts, the throughput exhaustion, the partial results, traces back to a filter you did not apply rather than to a page you asked for. Filters are not only a relevance tool. They are the primary throughput tool on the endpoint.

    Typing the court name or the year into the query string, so the engine hunts for them in judgment text instead of filtering on metadata
    Adding query terms to reduce noise, which quietly removes every judgment that made the point in other words
    Treating a judge name filter as exhaustive when honorifics, initials and registry spellings vary across the record
    Assuming caseType matches literally when a primary type is expanded server side into several registry codes
    Sending a date in any format other than strict YYYY-MM-DD and collapsing the validation details into a generic error
    Reading a thin result set over an older or District Court period as an engine failure rather than as sparse upstream metadata

    Why Filters Beat Any Ranking Tweak

    It is tempting to think that a noisy result set is a ranking problem, and that the answer is a better scoring model. Sometimes it is. Far more often, in Indian case law specifically, the noise has a structural cause that no ranking function can address: the result set is drawn from too many courts, too many decades and too many kinds of proceeding for any single ordering to serve the user's actual question.

    Consider a search under section 138 of the Negotiable Instruments Act 1881. The point is litigated continuously across the District Courts, appealed through the High Courts, and visited periodically by the Supreme Court. An unfiltered query is a genuinely hard ranking problem, because there is no single correct ordering over a set that heterogeneous. Now filter to one High Court and a three year window. The set collapses to something a person can read, relevance ordering becomes meaningful because the candidates are comparable, and nothing relevant has been excluded on vocabulary grounds. The ranking function did not change. The question did.

    The same holds for a section 34 challenge under the Arbitration and Conciliation Act 1996, where the useful frame is usually one court's practice over a period, or for interim injunction jurisprudence under Order 39 of the CPC 1908, where the District Court and High Court treatments answer different practical questions. Commercial Courts Act 2015 matters and IBC 2016 proceedings before the NCLT and NCLAT are the same story again. In each case, court plus period plus case type does more for the result set than any amount of query craft, and it does it without costing you a single judgment that was written in unfamiliar language.

    The exact field list, validation rules and response shape are at the API documentation, and what the corpus covers across the Supreme Court, the 25 High Courts, the the district judiciary and the tribunals is set out at the API overview. If you are wiring search into an assistant rather than into your own client, the same filters are reachable through the tooling described at the MCP server page.

    Narrow with filters, not with more words

    Every extra term in a query is a judgment you may never see, and no ranking change gives it back. POST /search/cases on the CourtMesh API takes query as its only required field and then lets you constrain by court, case type with server side expansion into registry codes, case number, judge name with its aliases, year between 1947 and the current year, strict date windows, and a sort of relevance or date, over an index of roughly 310 million records sourced from official government portals. The full parameter reference is at the API documentation, coverage is set out at the API overview, and the same search is available to assistants through the MCP server.

    Explore CourtMesh
    SearchFiltersAPIJudgmentsDevelopers
    X LinkedIn