Every Office format, one endpoint.

Word, PowerPoint, Excel, RTF, OpenDocument — the breadth that per-format libraries and screenshot-reading VLMs both struggle to cover in one pipeline.

the-problem

Office documents aren't one format — they're a family: .docx and the legacy .doc binary format, .pptx and .ppt, .xlsx and .xls, plus the OpenDocument siblings (.odt/.ods/.odp) and .rtf. A 'parse Office docs' feature usually means five or six separate libraries, each with its own quirks, versioning, and failure modes. Vision-based extractors that treat every page as an image lose slide speaker notes, spreadsheet formulas, and the structural distinction between a table and a wall of text — breadth across office formats is exactly where they're weakest.

one-request-solution

txtfetch wraps Apache Tika's Office parsers behind one request: POST any file in the family, or point it at a URL, and get the same { status, extracted_text } response — slide notes, sheet contents, and body text included.

curl
curl -X POST https://api.txtfetch.com/v1/extract \
  -H "Authorization: Bearer $TXTFETCH_KEY" \
  -F file=@board-deck.pptx
Python
import os
import requests

with open("board-deck.pptx", "rb") as f:
    r = requests.post(
        "https://api.txtfetch.com/v1/extract",
        headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"},
        files={"file": f},
    )

print(r.json()["extracted_text"])
JavaScript
import { readFile } from "node:fs/promises";

const file = new Blob([await readFile("board-deck.pptx")]);
const form = new FormData();
form.append("file", file, "board-deck.pptx");

const res = await fetch("https://api.txtfetch.com/v1/extract", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` },
  body: form,
});

const { extracted_text } = await res.json();
console.log(extracted_text);
Go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

type extractResponse struct {
	Status        string `json:"status"`
	ExtractedText string `json:"extracted_text"`
}

func main() {
	f, err := os.Open("board-deck.pptx")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	var body bytes.Buffer
	writer := multipart.NewWriter(&body)
	part, err := writer.CreateFormFile("file", "board-deck.pptx")
	if err != nil {
		panic(err)
	}
	if _, err := io.Copy(part, f); err != nil {
		panic(err)
	}
	writer.Close()

	req, err := http.NewRequest("POST", "https://api.txtfetch.com/v1/extract", &body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY"))
	req.Header.Set("Content-Type", writer.FormDataContentType())

	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)
}

Or skip the download — pass a url parameter and txtfetch fetches the document server-side:

curl
curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/sales-workbook.xlsx" \
  -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/sales-workbook.xlsx"},
)

print(r.json()["extracted_text"])
JavaScript
const endpoint = new URL("https://api.txtfetch.com/v1/extract");
endpoint.searchParams.set("url", "https://example.com/sales-workbook.xlsx");

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/sales-workbook.xlsx")
	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": "..."
}

formats-covered

  • .docx
  • .doc
  • .pptx
  • .ppt
  • .xlsx
  • .xls
  • .odt
  • .ods
  • .odp
  • .rtf

faq

How do I extract text from a .docx file?
POST it as multipart form data to https://api.txtfetch.com/v1/extract with your API key in the Authorization header. The response is { "status": "success", "extracted_text": "..." }.
Can it read PowerPoint speaker notes, not just slide text?
Yes — Apache Tika extracts slide body text and speaker notes from .pptx/.ppt files, both included in the returned text.
Does it handle the legacy .doc and .xls binary formats too?
Yes. txtfetch covers both the modern XML-based Office formats and their legacy binary predecessors through the same endpoint.
What about OpenDocument files (.odt, .ods, .odp)?
Supported the same way — POST the file or its URL and get back the same JSON response shape as any other format.

go-further

Stop parsing. Start shipping.

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

Get started →