# Search

`GET /public/v1/search` (scope `search:read`) finds documents in your business's files by words, inside compounds too ("Stuhl" finds "Bürostuhl"), and by meaning ("office chairs" finds "Bürostühle"). Deleted files are left out. It finds documents; it answers no questions and writes nothing.

## Parameters

| Parameter | Meaning |
| --- | --- |
| `q` | Required, 1 to 200 characters. |
| `kind` | A public kind (`invoice`, `credit_note`, `delivery_note`, `contract`, …); repeat for several. |
| `since`, `until` | Issue date, ISO 8601, inclusive. |
| `party` | Any party's name as read; case, umlauts and legal forms don't matter ("Müller Sanitär GmbH" finds "MUELLER SANITAER G.m.b.H."). |
| `vat_id` | A party's VAT ID as read, ignoring spaces and case. |
| `match` | `hybrid` (default): words and meaning; `keywords`: words only; `meaning`: meaning only; `exact`: only documents holding `q` as written (case, accents and spacing aside), never one that only means the same. |
| `due_since`, `due_until` | An invoice's due date, ISO 8601, inclusive. |
| `gross_min`, `gross_max` | The gross in your business's currency (converted at the ECB's rate), inclusive. |
| `direction` | `incoming` (from suppliers) or `outgoing` (to customers). |
| `status` | An invoice's: `open` (unpaid) or `paid`. |
| `category` | An ECLASS code of any level, eight digits (`24000000`): documents with a line in it or under it. |
| `limit`, `offset` | 1 to 50, default 20; `offset` up to 250. |

## Results

One per document, best first; a file without a document comes as itself.

- `document_id`, `file_id`, `file_name`, `kind`, `number`, `seller`, `buyer`, `issue_date`, `gross`, `currency`, `pages`
- `passages[]`, up to 5: `page`, `text` (about 300 characters), `highlights` (`[start, end)` ranges of the matched words in `text`, to mark), `found_by` (`words`, `meaning`, `both`)
- `facts[]`: card facts holding the words
- `file_url`, `document_url`: the file and document in this API

`total` counts the matches (Ocost ranks the best 300), `truncated` says there were more. `meaning: "unavailable"`: search by meaning is building or unreachable; words still answer.

## Examples

```bash
curl -sS -G https://api.ocost.io/public/v1/search \
  -H "Authorization: Bearer $OCOST_KEY" \
  --data-urlencode "q=Wartungsvertrag Aufzug" \
  --data-urlencode "kind=contract" \
  --data-urlencode "since=2025-01-01"
```

```python
found = session.get(
    f"{API}/search",
    params={"q": "Bürostuhl", "party": "Musterbüro Lieferant", "limit": 10},
    timeout=15,
).json()
for r in found["results"]:
    first = r["passages"][0] if r["passages"] else None
    print(r["number"], r["seller"], r["issue_date"], first and first["page"])
```

```javascript
const params = new URLSearchParams({ q: 'Skonto', kind: 'invoice' });
const found = await fetch(`${API}/search?${params}`, { headers: auth }).then((r) => r.json());
for (const r of found.results) console.log(r.number, r.file_url);
```
