Source: https://legiscore.in/docs

# Government land and property records, one REST API

Search official registers across Indian states. Submit a search, poll or receive a webhook, and fetch the result with its source documents. Credits are charged per search and refunded automatically when a search fails.

Base URL: `https://legiscore.in/api/v1`

Success is `{ "data": ... }`. A failure is `{ "error": { "code", "message" } }`. 422 and 429 follow RFC 9457 problem details.

## How it works

1. Find the search: browse [States](https://legiscore.in/docs/states) or call the public [catalog](https://legiscore.in/docs/api/catalog).
2. Resolve names to codes with a [lookup](https://legiscore.in/docs/api/lookups) and pass the code it returns.
3. Submit: `POST /api/v1/search` returns a search id straight away.
4. Poll `GET /api/v1/search/{id}` or give a `callback_url`. Download source documents from the result.

On searches marked Register, `found: false` only means no per-property match was computed. The documents are the deliverable.

## Copy setup instructions

```text
You are integrating the LegiScore Search API: government land and property record searches across Indian states.

Full documentation (read it before writing code): https://legiscore.in/docs
Machine-readable: https://legiscore.in/docs/llms-full.txt (all pages) and https://legiscore.in/docs/llms.txt (index). Any page as Markdown: https://legiscore.in/docs/md/<path>.

BASE URL
https://legiscore.in/api/v1

AUTHENTICATION
- Send "Authorization: Bearer <key>" (or "X-API-Key: <key>") on every request. Keys start with "lsk_".
- Read the key from the environment variable LEGISCORE_API_KEY. Never hardcode it, never log it, never ship it to a browser or mobile app.
- Only GET /api/v1/search/catalog works without a key.

FLOW: SUBMIT, POLL, RESULT
1. Find the search in the catalog: GET /api/v1/search/catalog?state=<state>. It lists each search_type, its fields, and whether it is live or held.
2. Submit: POST /api/v1/search with {"state", "search_type", "params", "label"?, "callback_url"?}. Add an Idempotency-Key header so a retry never double-charges. You get 202 and a search id (SRCH-...).
3. Poll GET /api/v1/search/{id} every 5 to 10 seconds, or pass an https callback_url and verify the X-LegiScore-Signature HMAC header. Stop when status is succeeded, failed or cancelled.
4. Read found, records and documents. Download a document with GET /api/v1/search/{id}/documents/{filename} (302 to a one-hour signed URL).
- found:false on a search marked "Register" does NOT mean the property is clear. Read the documents.
- Some searches use an OTP. LegiScore handles it; the status may show awaiting_otp for a short time. Do nothing.

LOOKUPS: SEARCH BY NAME, THEN SEARCH
- Where a field needs a place or office code, find it by NAME with GET /api/v1/search/lookups?state=<state>&dim=<lookup type>&q=<name>. The lookup type is named on each search page.
- Send q (2 characters or more). At most 10 matches return. Rate limit: 120 lookups a minute per key.
- Take the code from the chosen match's "meta" and pass it in params.
- NEVER try to list everything in a lookup, page through it, or loop over letters to enumerate it. That is not supported and will be refused or rate limited.

ERRORS AND REFUNDS
- Every error is {"error": {"code", "message"}}. 422 invalid_params and 429 follow RFC 9457; read invalid_params[] and fix the named field. A 422 is never charged.
- 429: wait Retry-After seconds, then retry. 402 insufficient_credits: stop and tell the user to top up.
- A search that fails or is cancelled is refunded automatically. A search that is HELD is refused with 422 search_unavailable before any charge.
- Check GET /api/v1/search/credits for the wallet balance.

When unsure about a search's parameters, fetch its page: https://legiscore.in/docs/states/<state>/<search-type-with-dashes>.
```
