---
name: Lighton
description: Use when building document search, retrieval-augmented generation (RAG), document parsing, or structured data extraction features. Reach for this skill when you need to ingest documents, search them semantically, ask questions over them with grounded answers, parse documents to Markdown, or extract typed fields from documents.
metadata:
    mintlify-proj: lighton
    version: "1.0"
---

# LightOn Developers API Skill

## Product summary

LightOn is a REST API for document search, retrieval-augmented generation (RAG), parsing, and structured extraction. Upload documents once and search them in milliseconds using hybrid semantic + lexical retrieval with reranking. Ask questions and get grounded answers with citations. Parse documents to clean Markdown or extract typed fields using JSON Schema. The API handles the full document-understanding pipeline—OCR, chunking, embedding, indexing—so you don't manage vector databases or embedding models yourself.

**Key endpoints:** `POST /api/v3/files` (upload), `POST /api/v3/search` (retrieve), `POST /api/v3/ask` (RAG), `POST /api/v3/parse` (convert to Markdown), `POST /api/v3/extract` (pull typed fields). All requests require `Authorization: Bearer $LIGHTON_API_KEY` header. Base URL: `https://api.lighton.ai/api/v3/`.

**Primary docs:** https://developers.lighton.ai

## When to use

Reach for this skill when:
- A user asks you to build a searchable document corpus or knowledge base
- You need to retrieve relevant passages from documents based on a natural-language query
- You're building a RAG system and need both retrieval and generation
- You need to convert PDFs, Office files, or images to clean Markdown
- You need to extract structured data (invoices, forms, contracts) into typed fields
- You're organizing documents with workspaces (multi-tenant isolation), tags (cross-workspace collections), or facets (structured metadata)
- You need to scope search/ask to specific documents, workspaces, or tagged collections
- A user mentions "I need to search my documents" or "I want to ask questions over my files"

## Quick reference

### Authentication
All requests require a bearer token. Create an API key from the console or via `POST /api/v3/keys`.

```bash
export LIGHTON_API_KEY=your_key_here
curl https://api.lighton.ai/api/v3/search \
  -H "Authorization: Bearer $LIGHTON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "vacation policy", "max_results": 3}'
```

### Core workflow: upload → search → ask
1. **Upload** a file: `POST /api/v3/files` with `workspace_id` and file. Returns immediately with `status: pending`.
2. **Poll** for completion: `GET /api/v3/files/{id}` until `status: embedded` (typically seconds).
3. **Search** or **Ask**: `POST /api/v3/search` or `POST /api/v3/ask` with `query` and optional `workspace_id`, `tag_id`, or `file_id`.

### File upload
```python
response = requests.post(
    "https://api.lighton.ai/api/v3/files",
    headers={"Authorization": f"Bearer {api_key}"},
    data={"workspace_id": 42},
    files={"file": open("document.pdf", "rb")},
)
file_id = response.json()["id"]
```

**Supported formats:** pdf, docx, xlsx, pptx, txt, html, png, jpg, csv, and more. See API reference for full list.

### Search
```python
response = requests.post(
    "https://api.lighton.ai/api/v3/search",
    headers={"Authorization": f"Bearer {api_key}"},
    json={
        "query": "What is the JWT token expiry policy?",
        "workspace_id": [42],  # optional: scope to workspace
        "max_results": 10,
    },
)
for result in response.json()["results"]:
    print(result["content"], f"score: {result['score']:.2f}")
```

### Ask (RAG in one call)
```python
response = requests.post(
    "https://api.lighton.ai/api/v3/ask",
    headers={"Authorization": f"Bearer {api_key}"},
    json={
        "query": "What is our incident response policy?",
        "workspace_id": [42],
        "model": "mistral-large-latest",  # or "alfred-ft5"
    },
)
print(response.json()["answer"])
for source in response.json()["results"]:
    print(f"  ↳ {source['source']['filename']}, p.{source['source']['page_start']}")
```

### Parse (document → Markdown)
```python
response = requests.post(
    "https://api.lighton.ai/api/v3/parse",
    headers={"Authorization": f"Bearer {api_key}"},
    files={"file": open("report.pdf", "rb")},
)
pages = response.json()["result"]["pages"]
markdown = "\n\n".join(p["markdown"] for p in pages)
```

For large documents (>20 MB, >15 pages), set `"options": {"async": true}` and poll `GET /api/v3/parse/{id}`.

### Extract (document + schema → typed fields)
```python
response = requests.post(
    "https://api.lighton.ai/api/v3/extract",
    headers={"Authorization": f"Bearer {api_key}"},
    json={
        "document": "https://example.com/invoice.pdf",
        "schema": {
            "type": "object",
            "properties": {
                "invoice_number": {"type": "string"},
                "total": {"type": "number"},
            },
        },
    },
)
data = response.json()["result"]["data"]  # one object per page
```

For large documents, set `"options": {"async": true}` and poll `GET /api/v3/extract/{job_id}`.

### Workspaces, tags, facets

| Feature | Use case | Scope | Permission boundary |
|---------|----------|-------|---------------------|
| **Workspaces** | Isolate teams, customers, tenants | One per file | Yes: API keys can be scoped per workspace |
| **Tags** | Cross-cutting collections (project, topic) | Many per file, across workspaces | No |
| **Facets** | Structured metadata with schema (type, attributes) | Many per file, across workspaces | No |

**Create workspace:**
```python
response = requests.post(
    "https://api.lighton.ai/api/v3/workspaces",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"name": "Engineering Team"},
)
workspace_id = response.json()["id"]
```

**Create tag:**
```python
response = requests.post(
    "https://api.lighton.ai/api/v3/tags",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"name": "Project Alpha", "description": "..."},
)
tag_id = response.json()["id"]
```

**Assign tags to file:**
```python
requests.post(
    f"https://api.lighton.ai/api/v3/files/{file_id}/tags",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"tags": [tag_id]},
)
```

**Scope search/ask to workspace or tag:**
```python
json={
    "query": "...",
    "workspace_id": [42],  # search only workspace 42
    "tag_id": [7],         # and/or only tag 7
}
```

### Search response fields

| Field | Meaning |
|-------|---------|
| `content` | The matched passage text |
| `score` | Overall fused relevance score (0–1, higher is better) |
| `scores.text` | Text embedding similarity |
| `scores.keyword` | BM25 lexical match |
| `scores.relevance` | Cross-encoder reranker confidence |
| `source.filename` | Original filename |
| `source.page_start`, `page_end` | Page range |
| `source.tags` | Tags on the file |

## Decision guidance

### Search vs Ask
| Situation | Use |
|-----------|-----|
| User asks a straightforward question, wants a single grounded answer | **Ask** — one retrieval, one generation, fixed prompt |
| You need to drive generation yourself, multi-step retrieval, custom prompts, or your own model | **Search** — get passages, feed to your own LLM in a loop |
| You want to inspect the raw passages before showing them to the user | **Search** |

### Parse vs Extract
| Situation | Use |
|-----------|-----|
| Convert a document to clean text for your own processing | **Parse** — returns Markdown per page |
| Pull specific typed fields from a document (invoice number, total, date) | **Extract** — returns structured JSON matching your schema |
| Process a stack of identical forms or invoices | **Extract** — applies schema to every page independently |

### Sync vs Async (Parse/Extract)
| Situation | Use |
|-----------|-----|
| Document ≤20 MB, ≤15 pages | **Sync** — blocks, returns result immediately |
| Document >20 MB or >15 pages | **Async** — returns job ID, poll for result |

### Workspace vs Tag vs Facet
| Situation | Use |
|-----------|-----|
| Different data needs different permission levels (multi-tenant) | **Workspace** — only permission boundary |
| Group files across workspaces by project or topic | **Tag** — flat, no schema |
| Precise structured queries (type, attributes, filters) | **Facet** — typed, hierarchical, queryable |

## Workflow

### Build a searchable knowledge base
1. **Create a workspace** (optional, for isolation): `POST /api/v3/workspaces`
2. **Upload documents**: `POST /api/v3/files` with `workspace_id`, poll `GET /api/v3/files/{id}` until `status: embedded`
3. **Optionally tag documents**: `POST /api/v3/files/{id}/tags` to group into collections
4. **Search**: `POST /api/v3/search` with `query`, optionally scoped by `workspace_id` or `tag_id`
5. **Ask**: `POST /api/v3/ask` for grounded answers with citations

### Build an agentic RAG loop
1. **Initialize**: set up a list to track retrieved passages
2. **Loop**: call `POST /api/v3/search` with a query, collect passages
3. **Decide**: pass passages to an LLM with a tool definition for search
4. **Repeat**: if the LLM calls search again, go to step 2; otherwise, return its answer

### Extract structured data from documents
1. **Define schema**: write a JSON Schema describing the fields you want
2. **Call extract**: `POST /api/v3/extract` with document (file or URL) and schema
3. **For large documents**: set `options.async: true`, poll `GET /api/v3/extract/{job_id}` until done
4. **Read results**: `result.data` is an array, one object per page

### Parse a document to Markdown
1. **Call parse**: `POST /api/v3/parse` with file or URL
2. **For large documents**: set `options.async: true`, poll `GET /api/v3/parse/{id}` until done
3. **Concatenate pages**: join `result.pages[*].markdown` in index order

## Common gotchas

- **Polling too aggressively**: file ingestion, parsing, and extraction are async. Poll every 2–5 seconds, not every 100ms. Recommended: 1s for first 10s, then 5s, capped at 30s.
- **Forgetting to poll for file status**: upload returns immediately with `status: pending`. You must poll `GET /api/v3/files/{id}` until `status: embedded` before searching.
- **Mixing workspace_id and file_id**: they are mutually exclusive. Use one or the other, not both.
- **Mixing file_id with tag_id**: also mutually exclusive. Use `workspace_id` + `tag_id` together, or `file_id` alone.
- **Assuming extract returns one object per document**: it returns one object **per page**. For multi-page documents, you get an array of objects.
- **Not handling 429 (rate limit)**: the API enforces rate limits. Implement exponential backoff and retry.
- **Ignoring error codes**: use the `error` field (not `detail`) for programmatic handling. `detail` may change between versions.
- **Passing unsupported file formats**: check the API reference for accepted formats. Unsupported types return 400.
- **Exceeding context window on Ask**: if query + retrieved context is too large, you get `context_length_exceeded`. Reduce `max_results` or use `workspace_id`/`tag_id` to narrow scope.
- **Forgetting API key in header**: all requests require `Authorization: Bearer $LIGHTON_API_KEY`. Missing it returns 401.
- **Assuming Ask is multi-turn**: Ask runs one retrieval and one generation. For conversational or multi-step RAG, use Search in your own loop.
- **Not checking file MIME type**: some endpoints (e.g., vision search) require documents to have been indexed with vision embeddings. Check `status_vision` field.

## Verification checklist

Before submitting work with LightOn:

- [ ] API key is set as environment variable or passed securely (never hardcoded)
- [ ] All requests include `Authorization: Bearer $LIGHTON_API_KEY` header
- [ ] File uploads poll `GET /api/v3/files/{id}` until `status: embedded` before searching
- [ ] Search/Ask requests use correct scoping: `workspace_id` OR `tag_id` + `workspace_id`, never `file_id` with either
- [ ] Extract/Parse async jobs poll with recommended cadence (1s → 5s → 30s cap)
- [ ] Error handling checks the `error` field, not `detail`, for programmatic logic
- [ ] Rate limit handling includes exponential backoff and retry logic
- [ ] Workspace/tag/facet IDs are verified to exist before use
- [ ] File formats are in the supported list (pdf, docx, xlsx, pptx, txt, html, png, jpg, csv, etc.)
- [ ] For Ask, verify the model name is one of: `mistral-large-latest` or `alfred-ft5`
- [ ] For Extract, JSON Schema is valid and uses supported types (string, number, boolean, date, etc.)
- [ ] Response handling accounts for `null` values in search results (e.g., vision chunks have `content: null`)

## Resources

**Comprehensive page-by-page navigation:** https://developers.lighton.ai/llms.txt

**Critical documentation pages:**
- [Quickstart](https://developers.lighton.ai/quickstart) — upload, search, ask in 5 minutes
- [From documents to answers](https://developers.lighton.ai/tutorials/from-documents-to-answers) — RAG concepts and endpoint mapping
- [API Reference](https://developers.lighton.ai/api-reference/introduction) — complete endpoint schemas and error codes

---

> For additional documentation and navigation, see: https://developers.lighton.ai/llms.txt