# eCourtsIndia Partner API — machine-readable reference Last verified: 2026-08-29 (live; case-search Solr map + electoral map) Human guide: https://blogs.ecourtsindia.com/2026/05/18/how-to-use-ecourtsindia-api/ Interactive docs: https://ecourtsindia.com/api/docs Pricing: https://ecourtsindia.com/api/pricing MCP setup: https://ecourtsindia.com/api/mcp Public search (no key): https://ecourtsindia.com/search This file is the complete partner-API knowledge base for humans and AI assistants. Do not invent endpoints, query params, or error codes. If a field is not listed here, call GET /api/partner/search/capabilities or GET /api/partner/enums or GET /api/partner/electoral/capabilities. Coverage claim to keep consistent with product copy: 28 crore+ Indian court cases; Supreme Court, all 25 High Courts, district/taluka courts, 18 tribunal types. ================================================================================ 1. BASE, AUTH, SHAPE, LIMITS ================================================================================ Base URL: https://webapi.ecourtsindia.com Auth header (required on partner routes unless docs mark an exception): Authorization: Bearer eci_live_<32 alphanumeric> Token is 41 characters including the eci_live_ prefix. Missing "Bearer " → 401 INVALID_TOKEN. JSON envelope: { "data": { ... }, "meta": { "request_id": "..." } } Docs examples may also show meta.requestId (camelCase). Log whichever key the client receives. Quote request_id to support. Dashboard shows the full request log. Rate limits (defaults; Enterprise can raise): 100 / minute, 3,000 / hour, 50,000 / day, 10 concurrent 429 RATE_LIMIT_EXCEEDED → exponential backoff (1s, 2s, 4s) + jitter 429 TOO_MANY_CONVERSIONS (order-md only) → honour Retry-After exactly Billing: metered per successful request unless marked free below. Failed INTERNAL_ERROR, invalid paging, and similar client 400s on electoral/search are typically not charged. Failed refreshes are refunded (status.refunded = true). Confirm live rates at /api/pricing before modelling volume. Snapshot Aug 2026 (confirm live): case detail ₹0.50 Ent / ₹1.50 PAYG; refresh ₹0.05 / ₹0.15 per CNR; cause-list CNR batch ₹0.10 / ₹0.30 per CNR. There is no unlimited flat monthly API plan. ================================================================================ 2. INVENTORY — 17 PARTNER ENDPOINTS ================================================================================ Family A — Cases (9) GET /api/partner/case/{cnr} metered GET /api/partner/search metered GET /api/partner/search/capabilities FREE GET /api/partner/case/{cnr}/order/{filename} metered GET /api/partner/case/{cnr}/order-ai/{filename} metered GET /api/partner/case/{cnr}/order-md/{filename} metered POST /api/partner/case/{cnr}/refresh metered, 202, POST not GET POST /api/partner/case/bulk-refresh metered, 2–50 CNRs POST /api/partner/case/bulk-refresh-status FREE, 1–50 CNRs Family B — Causelist (4) GET /api/partner/causelist/court-structure/* FREE with Bearer GET /api/partner/causelist/search metered, offset pagination POST /api/partner/causelist/cnr/batch metered per distinct CNR, 1–100 GET /api/partner/causelist/available-dates FREE with Bearer, needs a location filter Family C — Electoral (3) GET /api/partner/electoral/search metered, flat per request GET /api/partner/electoral/epic/{epic} same shape/charge as search GET /api/partner/electoral/capabilities FREE Plus: GET /api/partner/enums FREE (docs: callable without auth; still send Bearer in production clients) BREAKING: /api/CauseList/court-structure/* is NOT a partner path. Use /api/partner/causelist/court-structure/*. REST has NO query param named `cc`. That alias exists on MCP search_cases only. On REST, pass courtCodes (repeat the key). ================================================================================ 3. CASE DETAIL — GET /api/partner/case/{cnr} ================================================================================ CNR = 4 letters + 12 digits, e.g. DLHC010001232024 = Delhi High Court, case 000123, filed 2024. Sample used in docs: DLHC010001232024 (WP(C) 138/2024, Delhi HC, real case). Returns full record: parties, advocates, judges, hearings, orders, IAs, tagged matters. Party / advocate / judge fields are ARRAYS, not strings. registrationNumber = human case number (e.g. 138/2024). Display this. courtCaseData.caseNumber = internal DB id. Do not show users. Order files: judgmentOrders[].orderUrl / interimOrders[].orderUrl = BARE filename, e.g. "order-1.pdf" files.files[].pdfFile = internal storage key, e.g. "DLHC010001232024-order-1.pdf" files.files[].markdownContent = OCR-cleaned order text (use this first; no second call) files.files[].aiAnalysis = present when already generated Order endpoints MUST receive the bare orderUrl filename, not pdfFile. Prefixed names typically 404 ORDER_NOT_FOUND. 404 CASE_NOT_FOUND → valid CNR not in index yet. POST .../refresh to onboard, wait, GET again. 400 INVALID_CNR → not 16-char format. Stale-data rule: if nextHearingDate is before today AND case is not disposed/decided, OR nextHearingDate is null on a PENDING case, refresh before treating the snapshot as current. ================================================================================ 4. SEARCH — GET /api/partner/search ================================================================================ Solr full-text over metadata + aiKeywords + aiSummaryText + order markdown. One Solr document per CNR (uniqueKey=cnr). Partner query != every indexed field: do NOT send courtName=, filingNumber=, aiKeywords= as query params. Call GET /api/partner/search/capabilities (FREE) for the live catalog. query vs litigants vs caseNumbers (verified 29 Aug 2026, courtCodes=DLHC01): litigants=Shubham Pratap Singh → 2 hits (actual parties) query=Shubham Pratap Singh → 595 hits (order bodies / other mentions) query="Piyush Tyagi" → includes W.P.(C) 138/2024 where he is only cited in the order, not a party query=9623/2024 → did NOT find the writ whose FILING number is 9623/2024 (slash tokenised) caseNumbers=9623/2024 → 2 hits: filing-number match AND registration-number match (W.P.(C) 9623/2024) query=DLHC010001232024 → finds the CNR (copied into searchable_text) but GET /case/{cnr} is the right read courtLevels=TRIBUNAL works; there is still no courtType filter courtLocationFacetPath looks like 0/DL or 1/TN/05 — copy from a hit. Do NOT invent 0/26. query copies/searches: cnr, petitioners, respondents, advocates, judges, registrationNumber, benchType, caseCategory(+cleaned), judicialSection, actsAndSections, courtCode, courtName, caseStatus, caseType(+description), plus AI keywords/summaries and order markdown (live: cited names in orders match). filingNumber is indexed as an exact string but is NOT a reliable query match. Name fields use text_name (StandardTokenizer; trailing commas stripped). Indexed but not partner filters: courtName, caseTypeDescription, caseCategoryCleaned, courtCodeNumeric, courtNo, complexCode (sort/exists), aiKeywords (projectable), dataCleanerLastUpdated (sortable). Read order text from case detail, not search hits. Parameters are case-insensitive. Paging: page: 1-based, default 1 pageSize: default 20, partner max 200 (partnerMaxPageSize from capabilities) anonymous web cap is 50 (maxPageSize in capabilities) over 200 → 400 PAGE_SIZE_EXCEEDED, not charged walk page until hasNextPage is false NO cursor parameter on partner search Array params on REST: REPEAT THE KEY courtCodes=DLHC01&courtCodes=HCBM01 A comma inside one value is part of that value, not a separator. MCP search_cases: comma-separate in one string (caseTypes=WP_C,WP_CRL). MCP pageSize max is 200 (same partner ceiling as REST). TEXT / NAMES query full-text Solr. Operators WORK: "phrase", AND/OR/NOT (uppercase), parentheses, trailing wildcard neglig* Never start a term with * (full-index scan). Phrase+boolean works (earlier HTTP 500 bug is fixed; re-verified 2026-07-18). Prefer keywords + facets; operators for precision the facets cannot express. advocates, judges, petitioners, respondents, litigants repeatable; values OR'd. Inside each value, every token must match unless nameMatchMode is changed. Do NOT put Solr operators in name fields. nameMatchMode all (default) | any | phrase | fuzzy (edit distance 1 per token) applies only to those five name fields STRUCTURED FILTERS (repeatable arrays unless noted) courtCodes search-ready: DLHC01 not DLHC; NCLTMB0 not NCLTMB (trailing 0) caseTypes codes: WP_C not "Writ Petition" (case-sensitive) caseStatuses PENDING, DISPOSED, ... judicialSections CIV, CRIM, WRIT, REV, APP, MISC, PIL, BAIL, URG, ADM courtLevels SC | HC | DC | TRIBUNAL There is NO courtType search filter. Tribunals = courtCodes. caseNumbers normalised to N/YYYY; exact match on registration OR filing number. Accepts O.S./25794/2021, CRA 529/2007, 1763 of 2020. THIS is the Case Status clone. Query=138/2024 is ranked full-text, not exact. cnrs restrict to known CNRs stateCodes two-letter DL, MH — NOT numeric facet ids (26=Delhi in facet output) districtCodes numeric, from court-structure / get_districts benchTypes SB, DB, FB, CB, LB, SJ, PB, RB caseCategories enum codes as FILTERS; the caseCategory field ON a record is free-form court text actsAndSections exact stored text only (INDIAN PENAL CODE - 302). Prefer query=IPC 302 hasOrders, hasJudgments booleans filingYears, registrationYears, firstHearingYears, nextHearingYears, decisionYears minOrderCount / maxOrderCount, minHearingCount / maxHearingCount, minJudgmentCount / maxJudgmentCount, minIaCount / maxIaCount, minInterimOrderCount / maxInterimOrderCount, minCaseDurationDays / maxCaseDurationDays ⚠ minHearingCount is UNRELIABLE for High Court (hearingCount often 0). Use minOrderCount. Reliable for NCLT / tribunals. courtLocationPaths copy from result.courtLocationFacetPath (e.g. 0/DL, 1/TN/05). Do not invent numeric paths such as 0/26. DATES (YYYY-MM-DD) — all six pairs are live even if the docs accordion shows a subset filingDateFrom/To, registrationDateFrom/To, firstHearingDateFrom/To, nextHearingDateFrom/To, lastHearingDateFrom/To, decisionDateFrom/To FACETS / PROJECTION / PRESENCE / SORT facets: caseType, caseStatus, courtCode, stateCode, districtCode, filingYear, decisionYear, hasOrders, hasJudgments, benchType, courtLevel (also courtLocationFacetPath) includeFacetCounts default true; false = faster results-only maxFacetValues default 100, max 1000 facetPrefix, facetContains courtLocationFacetPrefix narrows location facet output only, does not filter hits yearFacetField filingYear|decisionYear + yearFacetGap (default 10, clamped 5–130) fields project; cnr always included existsFields / missingFields AND'd; unknown names ignored sortBy single field or chain: "orderCount desc,filingDate asc" unknown field → relevance, never an error sortOrder asc|desc includeExtremeDates default date-sort bound is [1900-01-01 TO NOW+2YEARS]; true lifts that bound Results at data.results[] (NOT data.cases[]). Response includes facets, totalHits, totalPages, hasNextPage, activeFilters, and enumDescriptions.enumLookup for labels in this page. Search results have no case title — build "Petitioner vs Respondent" from arrays. Name filters (judges/advocates/litigants/actsAndSections) WORK but often omit from activeFilters. Wrong courtCodes / caseTypes return ZERO rows with NO error. Validate via enums. Examples: # capabilities (free) GET /api/partner/search/capabilities # exact case number (preferred) GET /api/partner/search?courtCodes=DLHC01&caseTypes=WP_C&caseNumbers=138/2024 # litigant + court GET /api/partner/search?litigants=Virendra%20Vora&courtCodes=DLHC01&pageSize=200 # tribunal (no courtType filter) GET /api/partner/search?courtCodes=NCLTMB0&caseTypes=CP_IBC&courtLevels=TRIBUNAL # Solr operators GET /api/partner/search?query=%22specific%20performance%22%20AND%20injunction ================================================================================ 5. SEARCH CAPABILITIES — GET /api/partner/search/capabilities (FREE) ================================================================================ Live snapshot 2026-08-29 (same field lists as 23 Aug; still call the endpoint): sortableFields: score, dataCleanerLastUpdated, decisionDate, filingDate, registrationDate, firstHearingDate, lastHearingDate, nextHearingDate, caseDurationDays, orderCount, hearingCount, judgmentCount, interimOrderCount, iaCount, filingYear, decisionYear, filingToFirstHearingDays, caseType, caseStatus, caseCategory, benchType, courtCode, courtCodeNumeric, courtNo, districtCode, stateCode, complexCode, cnr, filingNumber, registrationNumber, judicialSection facetableFields: caseType, caseStatus, courtCode, stateCode, districtCode, filingYear, decisionYear, hasOrders, hasJudgments, benchType, courtLevel projectableFields: cnr, filingNumber, registrationNumber, caseType, caseStatus, courtCode, courtName, stateCode, districtCode, filingDate, registrationDate, firstHearingDate, nextHearingDate, decisionDate, lastHearingDate, petitioners, petitionerAdvocates, respondents, respondentAdvocates, judges, actsAndSections, judicialSection, caseCategory, caseCategoryFacetPath, benchType, aiKeywords, courtLocationFacetPath, hasOrders, hasJudgments, orderCount, interimOrderCount, judgmentCount, hearingCount, iaCount, caseDurationDays, filingToFirstHearingDays, filingYear, decisionYear existsFilterableFields: filingDate, registrationDate, firstHearingDate, nextHearingDate, decisionDate, lastHearingDate, dataCleanerLastUpdated, filingYear, decisionYear, caseDurationDays, filingToFirstHearingDays, orderCount, hearingCount, judgmentCount, interimOrderCount, iaCount, courtNo, courtCodeNumeric, complexCode, stateCode, districtCode, hasOrders, hasJudgments nameMatchModes: all, any, phrase, fuzzy courtLevels: SC, HC, DC, TRIBUNAL multiValueNameParams: Litigants, Petitioners, Respondents, Advocates, Judges yearFacetFields: filingYear, decisionYear maxPageSize: 50 (web) partnerMaxPageSize: 200 maxFacetValues: 1000 dateSortBound: [1900-01-01 TO NOW+2YEARS] unless IncludeExtremeDates=true Treat this endpoint as the live contract. Counts above are a snapshot. ================================================================================ 6. ORDER PDF / AI / MARKDOWN ================================================================================ GET /api/partner/case/{cnr}/order/{filename} Certified true-copy PDF (watermark + digital signature) by default. ?signed=false → raw court PDF, same cost. Download name switches to unsigned. GET /api/partner/case/{cnr}/order-ai/{filename} extractedText + structured aiAnalysis (summary, outcome, statutes, ratio, parties, counsel). First access 10–60s then cached. If aiAnalysis is null, wait 15–30s and retry (up to 3). Nested paths commonly used: aiAnalysis.intelligent_insights_analytics...ai_generated_executive_summary ...plain_language_summary_for_litigants_outcome_focused aiAnalysis.foundational_metadata.procedural_details_from_order.order_nature ...disposition_outcome_if_disposed aiAnalysis.foundational_metadata.core_case_identifiers.judge_names ...core_case_identifiers.order_date aiAnalysis.deep_legal_substance_context.core_legal_content_analysis.statutes_cited_and_applied ...arguments_and_reasoning_analysis.court_reasoning_for_decision GET /api/partner/case/{cnr}/order-md/{filename} Markdown + pdfBase64. Real-time conversion, up to 300s. 429 TOO_MANY_CONVERSIONS → Retry-After. Prefer files.files[].markdownContent on case detail for plain text. filename = order-1.pdf from orderUrl, NOT DLHC010001232024-order-1.pdf. 500/524 or null markdownContent = still fetching from government PDF servers. Wait 30–60s and call again (PDF is cached after first fetch). Persistent 404 / "unavailable at source": tribunal orders often have no live-scrape path; stop after 2–3 tries and use case metadata + any other orders. ================================================================================ 7. REFRESH ================================================================================ POST /api/partner/case/{cnr}/refresh Queues a live re-scrape of official government servers. Returns 202 immediately. GET .../refresh → 405 Method Not Allowed. Also ONBOARDS a valid CNR that is not in the index yet. Idempotent ~15 seconds (stray double-click does not double-charge). Typical landing time: 2–10 MINUTES (government servers), sometimes longer. Docs example estimatedTime "5-10 seconds" is optimistic metadata-only; do not promise that. Poll GET /api/partner/case/{cnr} until entityInfo.dateModified advances. Cap portfolio jobs at 10–15 minutes per CNR. POST /api/partner/case/bulk-refresh Body: { "cnrs": ["DLHC010001232024", "..."] } 2–50 CNRs. Deduplicates. Reports refreshed / queued / invalid. Chunk larger watchlists into 50. 400 EMPTY_REQUEST / TOO_MANY_CNRS POST /api/partner/case/bulk-refresh-status (FREE) Same body, 1–50 CNRs. Works for single or bulk queues. Statuses: PENDING, COMPLETED, FAILED, NOT_REQUESTED, INVALID FAILED includes refunded: true when credit was returned. Search index LAGS a successful refresh by up to 1–2 hours. Case detail updates quickly. Always compare watchlists off GET .../case/{cnr}, not search. "Searchable in ~30 seconds" is FALSE. Do not refresh every CNR every night. Refresh when: - nextHearingDate is in the past on a still-pending case - user clicks "get the latest" - you are onboarding an unknown CNR There are no webhooks. Pattern: snapshot caseStatus, nextHearingDate, lastHearingDate, orderCount, decisionDate → bulk-refresh stale CNRs → poll status → GET case → diff. ================================================================================ 8. ENUMS — GET /api/partner/enums (FREE) ================================================================================ ?types=caseType,caseStatus,courtCode,highCourtCode,stateCode,benchType,judicialSection,caseCategory,causeListType,courtType Cached ~1 hour. Do not hardcode. Live counts 2026-08-23: caseType 244 caseStatus 71 courtType 21 (SUPREME_COURT, HIGH_COURT, DISTRICT_COURT + 18 tribunal families: NCLT, NCLAT, ITAT, CGAT, CESTAT, DRT, SAT, DRAT, TDSAT, APTEL, JAGRITI, CCI, GST_AAAR, NGT, AFT, SEBI_ORDERS, RCT, GSTAT) highCourtCode 29 values including SCIN and UNKNOWN — these are BASE codes (DLHC), not search keys. Search needs DLHC01, HCBM01, HCMA01, KAHC01, UPHA01, WBCHCO, ... stateCode 37 (court-structure walk adds SC for Supreme Court = 38th jurisdiction key) courtCode ~10,280 establishments caseTypeRaw in responses ("W.P.(C)") is display. Filter with caseType code (WP_C). judicialSectionRaw ("APPELLATE SIDE") is display. Filter with APP. ================================================================================ 9. COURT STRUCTURE (FREE with Bearer) ================================================================================ GET /api/partner/causelist/court-structure/states GET /api/partner/causelist/court-structure/states/{state}/districts GET /api/partner/causelist/court-structure/states/{state}/districts/{districtCode}/complexes GET /api/partner/causelist/court-structure/states/{state}/districts/{districtCode}/complexes/{courtComplexCode}/courts High Courts appear as districtCode=HC. SC is the Supreme Court, labelled "India". 404 NOT_FOUND = guessed a code; walk from /states. ================================================================================ 10. CAUSE LIST ================================================================================ Window: roughly day-before through ~7 days ahead. Empty outside that window is expected. GET /api/partner/causelist/search Filters: q, listType=CIVIL|CRIMINAL, judge, advocate, litigant, state, districtCode, courtComplexCode, court, courtNo, date OR startDate+endDate, includeCourtroom=true courtNo = courtroom number; court = establishment id. Different values. Pagination: limit + offset (NOT page). First page offset=0. When returnedCount < limit, last page. Negative offset → 400 INVALID_OFFSET caseNumber and judge come back as ARRAYS. URL-encode / in case numbers as %2F (q=G.R.case%2F533%2F2023) Searching q by full case number is fragile; prefer advocate / judge / party name. Best path from a known CNR: POST .../causelist/cnr/batch POST /api/partner/causelist/cnr/batch Body: { "cnrs": ["DLHC010001232024"] } (1–100) Over 100 → 400 BATCH_SIZE_EXCEEDED Billed per distinct CNR. No single-CNR GET; batch with a one-item array. GET /api/partner/causelist/available-dates FREE with auth. At least one of: state, districtCode, courtComplexCode, court, courtNo. Else 400 MISSING_FILTER. ================================================================================ 11. ELECTORAL ROLL (Solr-backed; REST + MCP) ================================================================================ Different corpus from court cases. Do NOT send court state codes (DL). Use ECI codes (S01). One Solr document per roll occurrence. Partner params ≠ every indexed field. Call GET /api/partner/electoral/capabilities (FREE) or MCP get_electoral_capabilities. Do not invent village=, pincode=, serial=, pcNumber=, pollingStationNo=. MCP tools (same credits as REST; capabilities is free): search_electoral_roll lookup_epic (exact EPIC; same shape/charge as search) get_electoral_capabilities GET /api/partner/electoral/search Primary criterion REQUIRED or 400 MISSING_SEARCH_CRITERIA (not charged): name | epic | q | complete household key relativeName, age, gender, geography, roll filters only NARROW; they cannot start a search. Father's name alone is not a search — use q (or name) then filter. Household is exclusive: householdRollId + householdPartNumber + householdHouse together Copy the printed Household key from an occurrence (house, not a guessed houseNorm). Solr indexes houseNorm (punctuation stripped); send the printed house string. 400 HOUSEHOLD_INCOMPLETE if a part is missing 400 HOUSEHOLD_EXCLUSIVE if combined with name / relativeName / epic / q Paging: page and pageSize each 1–100. Out of range → 400 (PAGE_INVALID / PAGE_SIZE_INVALID / PAGE_EXCEEDED / PAGE_SIZE_EXCEEDED), rejected not clamped, not charged. Max reach 9,900 rows per query; narrow with filters. Charge is flat per successful request regardless of person count. Solr map (partner param → index): name → nameLatin, nameAlts, native name, nameFolded, namePhonetic nameMatchMode: all | any | phrase | fuzzy matchedOn: nameLatinExact, nameFolded, namePhoneticOnly relativeName → relativeLatin, relativeAlts, relative, relativeFolded, relativePhonetic matchedOn: relativeExact, relativeFolded, relativePhoneticOnly FILTER ONLY — cannot start a search q → searchable_text (copyField: nameLatin, nameAlts, relativeLatin, relativeAlts, name, relative, AND addressText) So q matches village / street / booth names, not just electors' names. epic → epic (exact). lookup_epic / GET .../epic/{epic} matchedOn: epicExact epicFuzzy → near-match on epic (OCR / photo). Nearby IDs, match ~90. household* → rollId + partNumber + house stateCode → ECI S01/S22/U05… NOT court DL districtCode → e.g. S0106 (not court district integers) acNumber, partNumber, age+ageTolerance, gender, relation, years, rollTypes, langCodes includeDeleted default true, excludeFlagged default false, groupByEpic default true gender filter: M | F | O. Live gender FACET can also return T; gender=T is rejected. relation: F Father, H Husband, M Mother. NOT FTHR. rollTypes seen live: FinalRoll, DraftRoll, SIR-FinalRoll. langCode ENG on English parts. Live capabilities (28 Aug 2026) — confirm with the free endpoint: nameMatchModes: all, any, phrase, fuzzy facets: gender, relation, year, rollType, langCode, deleted, geoFacetPath, stateCode, districtCode, acNumber, pincode, ageBand filters: StateCode, StateName, DistrictCode, DistrictName, AcNumber, PartNumber, Age+AgeTolerance, Gender, Relation, Years, RollTypes, LangCodes, IncludeDeleted, ExcludeFlagged, Household matchedOnValues: nameLatinExact, nameFolded, namePhoneticOnly, relativeExact, relativeFolded, relativePhoneticOnly, ageWithin2, ageWithinTolerance, stateMatch, districtMatch, pincodeMatch, epicExact maxPage / maxPageSize = 100 facetPrefix applies ONLY to geoFacetPath. Copy a path from a prior facet response; do not guess S01 as the prefix. pincode is a FACET (and pincodeMatch exists) but NOT a query filter. Indexed+returned but not filters: village, ward, tehsil, pcNumber, serial, pollingStationNo, sectionName, postOffice, policeStation. Person object: epic, Indic+Latin names, relative, relation (F/H/M), gender, approx year of birth, matchScore 0–100, matchedOn, occurrences[] with roll year/type, language, AC, part, serial, house, houseNorm, address, polling station, pincode, deleted, partFlags (e.g. part_identity_mismatch). matchScore/matchedOn ≠ same human. Do not merge EPICs on a name match. Live checks 28 Aug 2026: name=ramesh kumar&stateCode=S01 → 5753 persons (nameLatinExact) + relativeName=konaram → 1 person (nameLatinExact, relativeExact, stateMatch) q=kotturu&stateCode=S01 → ~89550 persons via addressText filters-only stateName=Odisha → 400 MISSING_SEARCH_CRITERIA, not charged household exclusive + name → 400 HOUSEHOLD_EXCLUSIVE GET /api/partner/electoral/epic/{epic} Exact EPIC. Same shape and charge as search. For near matches use search + epicFuzzy=true. GET /api/partner/electoral/capabilities (FREE) Authoritative field catalog. Do not hardcode this section if it drifts. Examples: GET /api/partner/electoral/search?name=ramesh%20kumar&stateCode=S01&age=35&pageSize=20 GET /api/partner/electoral/search?q=kotturu&stateCode=S01&pageSize=5 GET /api/partner/electoral/epic/ABC1234567 GET /api/partner/electoral/search?epic=ABC1234567&epicFuzzy=true GET /api/partner/electoral/search?householdRollId=ID&householdPartNumber=N&householdHouse=H GET /api/partner/electoral/capabilities ================================================================================ 12. MCP (same credits, different door) ================================================================================ URL: https://mcp.ecourtsindia.com/mcp (Streamable HTTP, NOT stdio) Preferred: OAuth Connect in the host. Leave Client ID / Secret empty. Fallback: ?token=YOUR_API_KEY if the host cannot do OAuth. Do not invent python -m ecourts_mcp_server. MCP — 30 tools (27 court + 3 electoral), verified 28 Aug 2026: Discovery: lookup_enum, fetch_live_enums, fetch_reference_file, get_search_capabilities, get_states, get_districts, get_complexes, get_courts Search: search_cases, search_and_get_first_case, search_and_brief_top_cases, search_causelist Case/order: get_case_details, get_case_brief, batch_get_case_details (max 20), get_case_with_latest_order, list_case_orders, get_order_markdown, get_order_ai_analysis Causelist: get_available_causelist_dates, check_cnr_causelist, get_court_docket Monitor: monitor_portfolio, refresh_case, refresh_and_wait_for_case, bulk_refresh_cases, check_refresh_status Electoral: search_electoral_roll, lookup_epic, get_electoral_capabilities (free) MCP search_cases pageSize max 200; REST partner max 200. Electoral page/pageSize remain 1–100. MCP `cc` = single court code convenience; REST uses courtCodes. Signed PDF download is REST-only (/order/{filename}). MCP has markdown + AI analysis. ================================================================================ 13. ERRORS ================================================================================ 401 INVALID_TOKEN missing/malformed Bearer 401 TOKEN_INACTIVE / TOKEN_EXPIRED 403 ACCOUNT_INACTIVE 402 INSUFFICIENT_CREDITS / SUBSCRIPTION_REQUIRED 400 INVALID_CNR 400 PAGE_SIZE_EXCEEDED >200 case search or >100 electoral 400 PAGE_INVALID / PAGE_SIZE_INVALID below 1 400 PAGE_EXCEEDED electoral page > 100 400 MISSING_SEARCH_CRITERIA 400 HOUSEHOLD_INCOMPLETE / HOUSEHOLD_EXCLUSIVE 400 EMPTY_REQUEST / TOO_MANY_CNRS bulk refresh (status) empty or >50 400 BATCH_SIZE_EXCEEDED cause-list batch >100 400 INVALID_OFFSET 400 MISSING_FILTER available-dates with no location 400/404 INVALID_FILENAME / ORDER_NOT_FOUND used prefixed pdfFile name 404 CASE_NOT_FOUND refresh to onboard if CNR is real 404 NOT_FOUND court-structure miss 405 refresh used GET 429 RATE_LIMIT_EXCEEDED / TOO_MANY_CONVERSIONS 500 INTERNAL_ERROR not charged; retry capped at 4 ================================================================================ 14. GOTCHAS (silent 200 + zero rows) ================================================================================ - DLHC → 0 hits. Use DLHC01. Bombay search key is HCBM01 (not MHHC01). - NCLTDL → 0 hits. Use NCLTDL0. - caseTypes="CIVIL" → 0 hits. Use WP_C / CS / ... - Query by name matches order bodies; use litigants for actual parties. - Punctuation in query is tokenised (A.P.A.C ≠ a literal). - Tribunal CNRs are derived; do not construct them. Search then take cnr from the hit. - High Court codes from enums (DLHC) are not search keys. - stateCode in FACETS is numeric; filter with two-letter codes. - Cause lists: encode slashes; stay inside the freshness window. - Electoral: no primary criterion → 400 MISSING_SEARCH_CRITERIA (not charged). - Electoral: relation is F/H/M not FTHR. gender filter is M|F|O (facet may show T). - Electoral: pincode is a facet, not a filter. Use q for village/street/booth. - Case search: litigants = parties only; query = orders too (2 vs 595 on a common name). - Case search: caseNumbers matches filing OR registration; query is not exact N/YYYY. - courtLocationFacetPath is 0/DL-style; do not send 0/26. - Electoral: q matches addressText as well as names — locality queries are huge; add stateCode. ================================================================================ 15. MINIMAL CLIENT RECIPES ================================================================================ Auth: curl -H "Authorization: Bearer eci_live_YOUR_TOKEN_HERE" \ https://webapi.ecourtsindia.com/api/partner/causelist/court-structure/states Case: curl -H "Authorization: Bearer eci_live_YOUR_TOKEN_HERE" \ https://webapi.ecourtsindia.com/api/partner/case/DLHC010001232024 Refresh then poll dateModified (expect minutes, not seconds). Bulk refresh 2–50, then POST bulk-refresh-status (free). Prefer caseNumbers for Case Status clones. Prefer litigants + nameMatchMode=fuzzy for party search. Prefer files.files[].markdownContent before order-md. Electoral: primary criterion required; ECI stateCode S01 not DL; q also matches address. GET /api/partner/electoral/capabilities (free) before inventing params. Keys: https://ecourtsindia.com/dashboard/settings Credits: https://ecourtsindia.com/dashboard/api-usage?tab=wallet Postman: https://www.postman.com/rchtjn2-5066313/ecourtsindia-api/collection/yhsdzy6/ecourtsindia-api Source: eCourts India — https://ecourtsindia.com Informational, not legal advice. Verify against the originating court record.