Source: https://legiscore.in/docs/quickstart

# Quickstart

Run your first search in three calls: check your balance, submit, then fetch the result. You need an API key and credits in your search wallet.

## 1. Check your balance

**curl**

```bash
curl "https://legiscore.in/api/v1/search/credits" \
  -H "Authorization: Bearer lsk_your_api_key"
```

**Python**

```python
import requests

resp = requests.get(
    "https://legiscore.in/api/v1/search/credits",
    headers={"Authorization": "Bearer lsk_your_api_key"},
)
resp.raise_for_status()
print(resp.json())
```

**Node**

```js
const resp = await fetch("https://legiscore.in/api/v1/search/credits", {
  method: "GET",
  headers: { Authorization: "Bearer lsk_your_api_key" },
});
if (!resp.ok) throw new Error(await resp.text());
console.log(await resp.json());
```

## 2. Submit a search

This looks up a housing project on the Andhra Pradesh RERA register by name. It takes plain text, so no lookup is needed.

**curl**

```bash
curl -X POST "https://legiscore.in/api/v1/search" \
  -H "Authorization: Bearer lsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
  "state": "andhra",
  "search_type": "rera",
  "params": {
    "search_term": "Aparna Amaravati One"
  },
  "label": "Quickstart test"
}'
```

**Python**

```python
import requests

resp = requests.post(
    "https://legiscore.in/api/v1/search",
    headers={"Authorization": "Bearer lsk_your_api_key"},
    json={
      "state": "andhra",
      "search_type": "rera",
      "params": {
        "search_term": "Aparna Amaravati One"
      },
      "label": "Quickstart test"
    },
)
resp.raise_for_status()
print(resp.json())
```

**Node**

```js
const resp = await fetch("https://legiscore.in/api/v1/search", {
  method: "POST",
  headers: { Authorization: "Bearer lsk_your_api_key", "Content-Type": "application/json" },
  body: JSON.stringify({
    "state": "andhra",
    "search_type": "rera",
    "params": {
      "search_term": "Aparna Amaravati One"
    },
    "label": "Quickstart test"
  }),
});
if (!resp.ok) throw new Error(await resp.text());
console.log(await resp.json());
```

You get 202 Accepted and a search object. Keep the id (for example SRCH-2026-A1B2C3D4), status is queued.

## 3. Fetch the result

Poll every 5 to 10 seconds until status is succeeded, failed or cancelled, or pass a callback_url when you submit.

**curl**

```bash
curl "https://legiscore.in/api/v1/search/SRCH-2026-A1B2C3D4" \
  -H "Authorization: Bearer lsk_your_api_key"
```

**Python**

```python
import requests

resp = requests.get(
    "https://legiscore.in/api/v1/search/SRCH-2026-A1B2C3D4",
    headers={"Authorization": "Bearer lsk_your_api_key"},
)
resp.raise_for_status()
print(resp.json())
```

**Node**

```js
const resp = await fetch("https://legiscore.in/api/v1/search/SRCH-2026-A1B2C3D4", {
  method: "GET",
  headers: { Authorization: "Bearer lsk_your_api_key" },
});
if (!resp.ok) throw new Error(await resp.text());
console.log(await resp.json());
```

Add an Idempotency-Key header to the submit call. A retry with the same key within 24 hours returns the original search and charges nothing.

## 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>.
```
