# Searching a document without reading it

Searching a converted document for literal substrings and getting addresses back instead of text.

`find` searches the converted document for literal substrings, ignoring case, and answers with the ADDRESSES of its matches - the part and the offset inside it - never the matched text. Whitespace inside `find` separates terms, and then a hit is a part where every term occurs, in any order: `find=pay court` answers the pages that discuss both, which is how a question about two words at once is asked without reading the document. One request tells an agent where something is; `part=N` then brings back only that piece, so a 500-page document is searched without ever travelling to the caller.

```
GET /?input=https://example.com/report.pdf&find=revenue&part=100-200
{"success":true,"result":"find","parts":{"count":500,"unit":"page"},
 "find":{"needle":"revenue","matches":2,"hits":[{"part":137,"offset":4021},{"part":188,"offset":96}]}}
```

| Field                | Meaning                                                                                                                                                                                                                                                                                                                          |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `find.needle`        | The search string that was given to `find`, trimmed. Whitespace inside it separates terms, so `find=pay court` asks a different question than `find=paycourt` - every term must occur in the same part, in any order, and case is ignored on every one of them                                                                   |
| `find.terms`         | With more than one term, and only when the answer is complete: one entry per term, in the order given, with how many of the searched parts carry it. It separates a term that is nowhere (`parts: 0`) from one that is everywhere, which `matches` alone cannot say when a term is missing. A count of parts, not of occurrences |
| `find.matches`       | How many matches the answer carries. `0` is an honest empty answer, never an error. With one term it counts occurrences, with several it counts parts where the terms meet                                                                                                                                                       |
| `find.hits[].part`   | The part the match sits in - the same 1-based numbering `part` accepts and `parts.count` describes. Absolute even when the request itself was scoped by `part`, so a hit always names the part to ask for                                                                                                                        |
| `find.hits[].offset` | 0-based character offset of the match from the start of that part. With one term it is that occurrence; with several it is the earliest of the terms, the way into that part. Part 1 counts from the start of the document, so the front matter it carries is numbered before its first chapter                                  |
| `find.hits[].terms`  | With more than one term: one entry per term, in the order given, carrying its own `count` and first `offset` inside this part - so a part found by one term can be read for how strongly it answers the others without fetching it                                                                                               |
| `find.truncated`     | These are not all the matches: the hit ceiling was reached, or the document itself was cut while it was built. Present only when true, and `find.terms` is withheld with it, so a partial count is never read as a total                                                                                                         |

A substring that does not occur is an honest empty answer (`matches: 0`), not an error, and a search string longer than 256 characters, or carrying more than 8 terms, is refused by name rather than answered with "no matches". With several terms `terms[]` says how many of the searched parts carry each one, so a term that is nowhere (`parts: 0`) is told apart from a term that is everywhere - and it is withheld with `truncated: true`, which marks an answer that is not the whole set of matches, so a partial count is never read as a total. Scope the search with `part`; hits keep their absolute part numbers, so `part=100-200&find=revenue` reports 137, never 38. `find` decides the answer, so `result` does not apply to it - and it is a conversion like any other, converting what it searches, so it costs and consumes exactly what the same request without `find` would. Ask for `result=meta` instead when only the part listing is needed, since that one converts nothing.

## Links

- **About service:** https://mdapi.io/about
- **API documentation and conversion:** https://mdapi.io
- **MCP server manifest:** https://mdapi.io/mcp
- **Health check:** https://mdapi.io/health
- **Documentation index:** https://mdapi.io/llms.txt
- **Full API documentation:** https://mdapi.io/llms-full.txt
- **AI discovery:** https://mdapi.io/.well-known/ai-discovery.json or https://mdapi.io/ai-discovery.json
- **AI Agent discovery:** https://mdapi.io/.well-known/agent.json or https://mdapi.io/agent.json
- **A2A Agent card:** https://mdapi.io/.well-known/agent-card.json or https://mdapi.io/agent-card.json
- **ACP manifest:** https://mdapi.io/.well-known/acp.json or https://mdapi.io/acp.json
- **x402 payment manifest:** https://mdapi.io/.well-known/x402.json or https://mdapi.io/x402.json
- **OpenAPI specification (JSON):** https://mdapi.io/.well-known/openapi.json or https://mdapi.io/openapi.json
- **OpenAPI specification (YAML):** https://mdapi.io/.well-known/openapi.yaml or https://mdapi.io/openapi.yaml
- **MAPI specification:** https://mdapi.io/.well-known/mapi.md or https://mdapi.io/mapi.md
- **Skill specification:** https://mdapi.io/.well-known/skill.md or https://mdapi.io/skill.md
- **Agent Plugins manifest:** https://mdapi.io/.well-known/plugin/plugin.json or https://mdapi.io/.well-known/plugin.json
- **Agent Plugins MCP config:** https://mdapi.io/.well-known/plugin/mcp.json
- **Agent Plugins conversion skill:** https://mdapi.io/.well-known/plugin/skills/mdapi-conversion/SKILL.md
- **API documentation pages:** https://mdapi.io/docs

## External Links

- **github.com** https://github.com/mdapiio/mdapi.io
- **skills.sh** https://www.skills.sh/mdapiio/mdapi.io
- **skillsmp.com** https://skillsmp.com/creators/mdapiio/mdapi.io
- **clawhub.ai** https://clawhub.ai/mdapiio
- **x.com** https://x.com/mdapiio

## Disclaimer

**The service is provided "AS IS".**


> mdapi.io is an edge-native service-transport primitive for AI, autonomous-agents, and the Web4 ecosystem.
