============================================================================== eCourtsIndia Partner API — Developer Reference for AI Assistants ============================================================================== PURPOSE: Paste this whole file into your AI coding assistant (ChatGPT, Claude, Cursor, Gemini, or your own model) as context. It lets the model answer questions and write code that matches the real eCourtsIndia API. It is a condensed, accurate companion to the full guide at: https://blogs.ecourtsindia.com/2026/05/18/how-to-use-ecourtsindia-api/ Last verified against the live API: 1 June 2026. Counts shown are illustrative and grow over time. ============================================================================== 1. WHAT THIS API IS ------------------------------------------------------------------------------ A REST interface to a structured layer of ~26.7 crore (267 million) Indian court records: Supreme Court, 25 High Courts, 700+ district courts, and major tribunals (NCLT, NCLAT, DRT). Records are deduplicated and refreshed from the official eCourts source. Orders/judgments are stored as digitally signed PDFs AND OCR-cleaned markdown, plus pre-computed AI analysis. Base URL: https://webapi.ecourtsindia.com Docs: https://ecourtsindia.com/api/docs (interactive Swagger) Pricing: https://ecourtsindia.com/api/pricing Dashboard: https://ecourtsindia.com/dashboard/settings (tokens + logs) 2. AUTHENTICATION (read this first — #1 cause of failed calls) ------------------------------------------------------------------------------ Every request needs a bearer token in the Authorization header. Token format: eci_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx CORRECT: Authorization: Bearer eci_live_xxx WRONG: Authorization: eci_live_xxx -> returns INVALID_TOKEN The literal word "Bearer" + one space + the token is REQUIRED. Sending the raw token, or no prefix, returns INVALID_TOKEN even when the token is valid. Tokens: - Create / view / rotate them yourself at the dashboard settings page. - You can create MULTIPLE tokens. Name each by use (production, staging, nightly-job) so you can read per-environment usage and revoke one without breaking others. - A token stays valid as long as the account has credit (no daily expiry). - If a token suddenly returns INVALID_TOKEN in production, it was probably rotated on the account: read the current token from the dashboard. - Treat tokens as secrets: env var in dev, secret manager in prod, never in a repo, never logged. Logging: every request (success or failure) is logged and visible in your dashboard (endpoint, timestamp, outcome). Every JSON response also contains meta.request_id. To get support help, send request_id + CNR. 3. CNR FORMAT ------------------------------------------------------------------------------ CNR (Case Number Record) is the 16-character unique case id. Example: DLHC010001232024 Pattern: 4 chars court code + 2 chars establishment + 6 digit number + 4 digit year. 4. ENUMS / REFERENCE DATA (do not hardcode; pull these) ------------------------------------------------------------------------------ GET /api/partner/enums?types=caseType,caseStatus,courtCode,stateCode (free) Returns authoritative dictionaries. Counts: 152 case types, 71 case statuses, 36 High Court codes, 37 state codes. WARNING — SILENT FAILURE: passing a caseType or courtCode that does not exist returns 0 results with HTTP 200 (no error). If a query is unexpectedly empty, verify your codes first. Common case type codes: WP_C (writ petition civil), CS (civil suit), CRL_A (criminal appeal), BA (bail), ABA (anticipatory bail), SLP_C (special leave petition civil), CC (criminal complaint), MACA (motor accident claims), PIL, COP (company petition). State codes: two letters (DL, MH, KA, TN, WB...). Supreme Court = SC. High Court codes carry a suffix: DLHC01 (Delhi), KAHC01 (Karnataka), HCBM01/HCBM02 (Bombay). NCLT uses a trailing 0: NCLTMB0 (Mumbai), NCLTDL0. Court hierarchy walk (for cause list codes): GET /api/CauseList/court-structure/states GET /api/CauseList/court-structure/states/{state}/districts GET /api/CauseList/court-structure/states/{state}/districts/{districtCode}/complexes GET /api/CauseList/court-structure/states/{state}/districts/{districtCode}/complexes/{courtComplexCode}/courts 5. ENDPOINT GROUPS ------------------------------------------------------------------------------ CASE RETRIEVAL GET /api/partner/case/{cnr} Returns full record: parties, advocates, judges, hearings, IAs, orders. The full OCR-cleaned order text is ALREADY in files.files[].markdownContent (no separate call needed). Per-order AI analysis in files.files[].aiAnalysis. ORDER RETRIEVAL (use the BARE filename from judgmentOrders[].orderUrl, e.g. "order-1.pdf") GET /api/partner/case/{cnr}/order/{filename} -> signed PDF GET /api/partner/case/{cnr}/order-md/{filename} -> OCR markdown GET /api/partner/case/{cnr}/order-ai/{filename} -> markdown + AI analysis NOTE: files.files[].pdfFile shows the prefixed storage name (DLHC010001232024-order-1.pdf). Do NOT pass that. Pass the bare orderUrl value (order-1.pdf). REFRESH POST /api/partner/case/{cnr}/refresh (single; POST not GET) POST /api/partner/case/bulk-refresh (body: {"cnrs":[...]}) SEARCH GET /api/partner/search (see section 6) CAUSE LIST GET /api/partner/causelist/available-dates?state=..&districtCode=..&courtComplexCode=.. GET /api/partner/causelist/search?q=..&state=..&advocate=..&judge=..&litigant=.. &date=..&startDate=..&endDate=..&limit=..&offset=.. 6. SEARCH — THE MOST MISUNDERSTOOD ENDPOINT ------------------------------------------------------------------------------ GET /api/partner/search (parameters are case-insensitive) Engine: Apache Solr full-text over a combined field that includes case metadata + AI keywords + AI summary + the FULL markdown text of every order. KEY PARAMETERS (PascalCase shown; lowercase also works): Query free-text Solr query (see operators below) Litigants party names only, BOTH petitioner and respondent sides Petitioners petitioner/appellant side only Respondents respondent/defendant side only Advocates advocate name Judges judge name CaseTypes comma-separated case type codes (WP_C,CS) CaseStatuses comma-separated status codes (PENDING,DISPOSED) CourtCodes comma-separated court codes (DLHC01) StateCodes comma-separated state codes (DL,MH) FilingYears comma-separated years (2024,2025) RegistrationYears / DecisionYears / NextHearingYears / FirstHearingYears FilingDateFrom / FilingDateTo (YYYY-MM-DD) and matching Registration/ Decision/FirstHearing/NextHearing/LastHearing date ranges HasOrders, HasJudgments booleans MinOrderCount / MaxOrderCount, MinHearingCount, MinCaseDurationDays... BenchTypes, JudicialSections, CaseCategories, ActsAndSections IncludeFacetCounts=true returns facet counts for a filter sidebar SortBy (filingDate|registrationDate|nextHearingDate|decisionDate), SortOrder (asc|desc) Page (1-based), PageSize (max 100, default small) RESPONSE: data.results[], data.totalHits, data.totalPages, data.hasNextPage, data.facets{...}, meta.request_id. --- NAME SEARCH: the three modes (verified counts for "Virendra Vora") --- Query=Virendra Vora (no quotes) -> ~12,319 hits. Full-text; matches the words "Virendra" OR "Vora" separately, anywhere, INCLUDING inside order text, advocate and judge names. Query="Virendra Vora" (quoted) -> ~103 hits. Exact phrase, still across all text fields including order bodies. Litigants=Virendra Vora -> ~205 hits. Party names only, petitioner AND respondent sides. RULE OF THUMB: - Want actual parties? Use Litigants (or Petitioners/Respondents for one side). - Litigants matches the name ANYWHERE in the party lists, regardless of position. Example: "Nemin Virendra Vora" via Litigants returns cases where the person is the 4th of several respondents. Using only Petitioners with the first party name MISSES these. - The general Query is full-text and will match a name mentioned inside an order even when the person is not a party. That is why a website "general search" shows far more results than a clean party search. --- "WEBSITE SHOWS 11,000 BUT API GAVE ME 150" --- Two causes stacked: (1) the website default is an unquoted general (full-text) search, which is the large number; (2) the API paginates (max 100/page). Read one page, get one page. Loop Page until hasNextPage is false. Use Litigants for the clean party set instead of the inflated full-text count. --- REPLICATE THE WEBSITE CASE STATUS SEARCH (State/District/Court/Type/Number/Year) --- There is NO separate case-status endpoint. Use facets on /search: State -> StateCodes Court -> CourtCodes Type -> CaseTypes Year -> FilingYears Case number -> Query Example: GET /api/partner/search?CourtCodes=DLHC01&CaseTypes=WP_C&FilingYears=2024&Query=138/2024 The facets filter precisely; the case number in Query is full-text, so the exact case RANKS FIRST rather than being the only row. Read the cnr from the top result, then GET /api/partner/case/{cnr} for the authoritative record. Without facets you get results from many states. --- OPERATORS (Solr) --- Phrase (exact): "specific performance" Boolean (UPPERCASE): murder AND weapon | tenant OR lessee | bail NOT anticipatory Grouping: (murder OR "culpable homicide") AND weapon Wildcard (trailing): neglig* (never START with *) Case-insensitive. Examples: Query="airtel" OR "Bharti Airtel" (quotes avoid matching "Bharti Mehta") Query="jio" AND "airtel" (~1,900 hits; Reliance Jio v Bharti Airtel) Punctuation note: tokens like A.P.A.C are split on dots in the default search; quote them ("A.P.A.C") for a literal match. URL-encode in code: space=%20, double-quote=%22, so "Virendra Vora" -> %22Virendra%20Vora%22. 7. REFRESH — SEMANTICS THAT TRIP PEOPLE UP ------------------------------------------------------------------------------ - POST, not GET. GET /refresh returns 405 Method Not Allowed. - ASYNCHRONOUS: refresh queues a re-scrape from the official eCourts source and returns immediately. Then poll GET /api/partner/case/{cnr} until data.entityInfo.dateModified advances. Cap the wait (e.g. 300s). - LATENCY varies: metadata-only updates settle in seconds; new order PDFs that need OCR, or a slow government server, can take a few minutes. - WHY IT CAN HICCUP: refresh reaches through to government court servers in real time. Those servers are not always fast or reliable; an occasional slow response or retry is the source, not your request. Poll + backoff. - REFRESH ADDS UNKNOWN CASES: if you refresh a valid CNR that is NOT yet in the eCourtsIndia database, the backend fetches it from source and adds it. Either single or bulk refresh works this way. Pattern for a missing CNR: refresh -> wait -> GET case. It will now be populated. - SEARCH INDEX LAG: after a refresh, the CASE endpoint reflects fresh data quickly, but the SEARCH index reindexes in batches (the dataset is huge), so a freshly refreshed/added case can take UP TO 1-2 HOURS to appear or update in /api/partner/search. For the freshest view of a specific case, read it by CNR, not via search. - BULK: for >2-3 cases use POST /api/partner/case/bulk-refresh with {"cnrs":[...]}. It validates, deduplicates, queues valid ones, reports invalid ones. Volume is governed by your plan. Python (refresh then poll): import time, requests BASE="https://webapi.ecourtsindia.com"; H={"Authorization":"Bearer eci_live_xxx"} def refresh_and_fetch(cnr, max_wait=300, poll=10): requests.post(f"{BASE}/api/partner/case/{cnr}/refresh", headers=H).raise_for_status() t0=time.time(); base=None while time.time()-t0 < max_wait: time.sleep(poll) r=requests.get(f"{BASE}/api/partner/case/{cnr}", headers=H); r.raise_for_status() m=r.json()["data"]["entityInfo"]["dateModified"] if base is None: base=m elif m!=base: return r.json() return r.json() 8. CASE UPDATE ALERTS (no webhooks yet — poll and compare) ------------------------------------------------------------------------------ Daily pattern: for each watched CNR, refresh + fetch, compare key fields to a stored snapshot, alert on change, save new baseline. Watch: caseStatus, nextHearingDate, lastHearingDate, orderCount, decisionDate. (orderCount up = new order/judgment; nextHearingDate change = relisted.) For a watchlist, bulk-refresh all CNRs first, then fetch+compare each. Compare off the CASE endpoint, not search (search lags 1-2h). Run on a daily cron. 9. CAUSE LISTS (real-world facts) ------------------------------------------------------------------------------ - WINDOW: roughly 1 day back to 7 days forward only. Lists change up to the hearing, so a date >7 days out returns empty BY DESIGN (not a bug). - SEARCH BY NAME, NOT CASE NUMBER: causelist/search matches advocates, judges, litigants, parties. A full case-number string (e.g. O.S./25794/2021) often returns empty even when listed, because cause-list rows are keyed differently from the case registry. Search by advocate/judge/party name instead. - BENCH vs ROOM: the "court number" (e.g. 21) is the court ESTABLISHMENT id, not a physical room. The useful fields are the bench/judge hearing the matter, which change over a case's life. Carry bench + judge through. - CASE -> CAUSE LIST MAPPING: build a table the first time you see a case (store CNR + establishment code + case number). When a hearing is within a few days, use that mapping to pick the cause-list row and surface bench/judge. 10. ERRORS ------------------------------------------------------------------------------ INVALID_TOKEN missing "Bearer" prefix, malformed, or rotated -> fix header / re-read token 401 unauthorized -> rotate token, update secret store 403 endpoint/resource not on your plan -> check pricing tier 404 CNR not in index or typo -> verify 16-char CNR; or refresh it to add it 405 wrong method -> refresh is POST not GET 429 rate limit -> exponential backoff with jitter 500 rare/transient or source-server hiccup -> retry w/ backoff (cap 4), send request_id to support Every response has meta.request_id; your dashboard logs every call. 11. PRICING MODEL (confirm current rates at /api/pricing) ------------------------------------------------------------------------------ - New accounts get free starter API credits. - Pay As You Go (PayG): pay per call at standard rates. - ENTERPRISE: ₹10,000/month subscription that becomes API credit. Per-call rates on Enterprise are typically ~1/3 of PayG, so credit goes ~3x further. * Monthly subscription credit is use-it-or-lose-it within the billing cycle (spend ₹8,000, the remaining ₹2,000 expires at cycle end). * TOP-UP anytime at the same Enterprise rate. Top-up credit DOES NOT EXPIRE and carries forward. * Spend order: monthly subscription credit is consumed FIRST; top-up is only drawn down once the monthly credit is used up. So top-up is safe — it is never wasted, it rolls into the next cycle. 12. QUICK ANSWERS ------------------------------------------------------------------------------ Q: Get all the codes? -> GET /api/partner/enums (free) + court-structure walk. Q: Search returns many states? -> add StateCodes/CourtCodes/CaseTypes/FilingYears. Q: Litigant vs Query? -> Litigants = party fields only; Query = full text incl. orders. Q: Only 100 results? -> paginate; max PageSize 100; loop Page until hasNextPage false. Q: Exact match? -> quote the phrase ("AU Small Finance Bank"). Q: Open order file? -> use bare orderUrl name (order-1.pdf); text already in markdownContent. Q: Refresh sync? -> no, POST + poll dateModified; can take minutes. Q: Refresh a CNR you don't have? -> it fetches and adds it from source. Q: Refreshed but search is stale? -> search reindex lags up to 1-2h; read by CNR. Q: Notifications? -> daily refresh+fetch+compare snapshot; no webhooks yet. Q: Cause list next month? -> no; window is -1 to +7 days. ============================================================================== Full guide: https://blogs.ecourtsindia.com/2026/05/18/how-to-use-ecourtsindia-api/ Search guide: https://blogs.ecourtsindia.com/2026/05/30/ecourtsindia-search-guide/ Litigant guide: https://blogs.ecourtsindia.com/2026/05/30/litigant-search-guide/ Due diligence build: https://blogs.ecourtsindia.com/2026/05/29/build-legal-due-diligence-ecourtsindia-api/ API home: https://ecourtsindia.com/api | Search: https://ecourtsindia.com/search ==============================================================================