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
curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/report.docx" \
  -H "Authorization: Bearer $TXTFETCH_KEY"
Python
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"])
JavaScript
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);
Go
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

Stop parsing. Start shipping.

Create an account and get an API key in minutes — the free Hobby plan needs no card.

Get started →