Every file in your document estate, made searchable.
Contracts, decks, spreadsheets, scanned forms — one extraction call turns each into indexable plain text, whatever landed in the folder.
the-problem
Search indexes are only as complete as the ingestion pipeline feeding them, and document estates are never one format: a shared drive has PDFs next to Word docs, Excel exports, and scanned paperwork someone photographed on a phone. Teams typically end up with format-specific handling for each — a PDF library for reports, an Office SDK for spreadsheets, a separate OCR queue for scans — and files that fall outside the covered set simply don't make it into the index, becoming permanent search blind spots.
how-txtfetch-solves-it
txtfetch gives every file type in the estate the same code path: POST it or point at its URL, and get back plain text ready to hand to your indexer's bulk API — Elasticsearch, OpenSearch, Algolia, Meilisearch, whatever you run. Scanned pages route through OCR automatically, so a folder of PDFs, Office files, and photographed forms indexes through one loop instead of three.
- One extraction call per document regardless of source format — no per-format indexer feed to maintain
- Automatic OCR for scanned and photographed documents, same request shape as any other format
- Pass a URL to index linked or attached documents without a separate download step
- Async job mode with webhook callback for indexing large batches without holding a connection open
- Idempotency-Key support so a retried indexing job doesn't double-index a document
curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/report.docx" \
-H "Authorization: Bearer $TXTFETCH_KEY"import os
import requests
r = requests.post(
"https://api.txtfetch.com/v1/extract",
headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"},
params={"url": "https://example.com/report.docx"},
)
print(r.json()["extracted_text"])const endpoint = new URL("https://api.txtfetch.com/v1/extract");
endpoint.searchParams.set("url", "https://example.com/report.docx");
const res = await fetch(endpoint, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` },
});
const { extracted_text } = await res.json();
console.log(extracted_text);package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
)
type extractResponse struct {
Status string `json:"status"`
ExtractedText string `json:"extracted_text"`
}
func main() {
endpoint, err := url.Parse("https://api.txtfetch.com/v1/extract")
if err != nil {
panic(err)
}
q := endpoint.Query()
q.Set("url", "https://example.com/report.docx")
endpoint.RawQuery = q.Encode()
req, err := http.NewRequest("POST", endpoint.String(), nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result extractResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
panic(err)
}
fmt.Println(result.ExtractedText)
}{
"status": "success",
"extracted_text": "..."
}faq
- Can txtfetch feed an Elasticsearch or OpenSearch index?
- Yes — POST each document (or its URL) to /v1/extract and hand the returned extracted_text straight to your indexer's bulk API; txtfetch doesn't talk to the index directly, it just gets you clean text to index.
- What happens to scanned documents in a search-indexing pipeline?
- They're OCR'd automatically via Tesseract — same request, same response shape as a digital-native file — so scanned paperwork ends up searchable alongside everything else without a separate OCR queue.
- How do I index a large batch without blocking on slow OCR jobs?
- Pass async=true (or use the SDK's extractAsync/extract_async) and either poll the job or supply a webhook_url — the indexing job submits the batch and picks up results as they complete instead of waiting synchronously.
related-reading
other-solutions
Stop parsing. Start shipping.
Create an account and get an API key in minutes — the free Hobby plan needs no card.
Get started →